package com.bestcem.xm.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.common.core.exception.ServiceException;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.component.security.dto.TokenDTO;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.user.constant.BusinessConstant;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.constant.UserGroupConstant;
import com.bestcem.xm.user.controller.vo.group.CreateGroupResponseVO;
import com.bestcem.xm.user.dao.OrganizationDao;
import com.bestcem.xm.user.dao.UserGroupDao;
import com.bestcem.xm.user.dao.UserGroupLevelDao;
import com.bestcem.xm.user.dao.mapper.UserAccountMapper;
import com.bestcem.xm.user.dao.mapper.UserGroupMapper;
import com.bestcem.xm.user.dao.mapper.UserUserGroupMapper;
import com.bestcem.xm.user.dao.mapper.XmUserRoleMapper;
import com.bestcem.xm.user.entity.mysql.Role;
import com.bestcem.xm.user.entity.mysql.User;
import com.bestcem.xm.user.entity.mysql.UserGroup;
import com.bestcem.xm.user.entity.mysql.UserUserGroup;
import com.bestcem.xm.user.entity.pojo.*;
import com.bestcem.xm.user.enums.*;
import com.bestcem.xm.user.grpc.client.BpSurveyQuotaGrpcService;
import com.bestcem.xm.user.grpc.service.param.*;
import com.bestcem.xm.user.mq.info.group.GroupNameInfo;
import com.bestcem.xm.user.mq.info.group.LevelNameInfo;
import com.bestcem.xm.user.mq.info.group.StoreInfo;
import com.bestcem.xm.user.mq.send.biz.UserMessageSendService;
import com.bestcem.xm.user.service.*;
import com.bestcem.xm.user.service.dto.PageResponseDTO;
import com.bestcem.xm.user.service.dto.group.*;
import com.bestcem.xm.user.service.dto.user.OrganizationDTO;
import com.bestcem.xm.user.service.dto.user.UserDTO;
import com.bestcem.xm.user.util.business.DataBaseUtil;
import com.bestcem.xm.user.util.business.GroupSequenceUtil;
import com.bestcem.xm.user.util.business.UserCacheUtil;
import com.bestcem.xm.user.util.business.UserGroupContextUtil;
import com.bestcem.xm.user.util.convert.UserGroupConvert;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.redisson.api.RLock;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.bestcem.xm.common.core.constant.ResourceErrorCodeConstants.OUT_OF_GROUP;
import static com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum.PERMISSION_DENY;
import static com.bestcem.xm.user.enums.GroupStatusEnum.GROUP_STATUS_ACTIVATED;
import static com.bestcem.xm.user.enums.GroupStatusEnum.GROUP_STATUS_INACTIVATED;

/**
 * 用户组服务·
 *
 * @author qiongyu.cui <qiongyu.cui@idiaoyan.com>
 * @version v1.0
 * @date 2021/12/29 11:00
 */
@Slf4j
@Service
public class UserGroupServiceImpl implements UserGroupService {
    @Resource
    private UserGroupDao userGroupDao;
    @Resource
    private UserCacheUtil userCacheUtil;
    @Resource
    private GroupSequenceUtil groupSequenceUtil;
    @Resource
    private OrganizationDao organizationDao;
    @Resource
    private UserGroupConvert userGroupConvert;
    @Resource
    private UserGroupLevelService userGroupLevelService;
    @Resource
    private UserUserGroupService userUserGroupService;
    @Resource
    private UserGroupService userGroupService;
    @Resource
    private UserGroupLevelDao userGroupLevelDao;
    //@Resource
    //private UserGroupMessageSender userGroupMessageSender;
    @Resource
    private UserService userService;
    @Resource
    private SequenceService sequenceService;
    @Resource
    private OrganizationService organizationService;
    @Resource
    private UserGroupMapper userGroupMapper;

    @Resource
    private UserUserGroupMapper userUserGroupMapper;

    @Resource(name = "executor")
    private Executor executor;

    @Resource
    private BpSurveyQuotaGrpcService bpSurveyQuotaGrpcService;

    @Resource
    private RedisService redisService;

    @Resource
    private UserAccountMapper userAccountMapper;

    @Resource
    XmUserRoleMapper xmUserRoleMapper;

    public static final String GROUP_INVALID_LOCK = "xm:user:group:invalid:";
    public static final String GROUP_RESUME_LOCK = "xm:user:group:resume:";

    @Resource
    private UserMessageSendService userMessageSendService;

    /**
     * 更新用户组状态
     *
     * @param groupId     用户组id
     * @param groupStatus 用户组状态
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Boolean> 更新结果：true：成功、false：失败
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2021/12/30 14:44
     */
    @Override
    public ServiceResult<Boolean> updateStatusById(String groupId, Integer groupStatus) {
        if (StringUtils.isEmpty(groupId) || Objects.isNull(groupStatus)) {
            return ServiceResult.fail("groupId和groupStatus都不能为空！");
        }
        return ServiceResult.success(userGroupDao.updateStatusById(groupId, groupStatus));
    }

    /**
     * 根据groupLevelId和groupIdList查询用户组列表
     *
     * @param levelId
     * @param groupIdList
     * @return com.bestcem.xm.util.ServiceResult<com.bestcem.xm.user.service.dto.group.UserGroupDTO>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/9 20:39
     */
    @Override
    public ServiceResult<List<UserGroupDTO>> listByLevelIdAndGroupIds(String levelId, List<String> groupIdList) {
        // 参数校验
        if (!ObjectId.isValid(levelId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "层级id不能为空或格式不正确");
        }
        if (ObjectUtil.isEmpty(groupIdList)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织id列表不能为空或格式不正确");
        }

        List<UserGroupDO> userGroupDOS = userGroupDao.listByLevelIdAndGroupIds(levelId, groupIdList);
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDOS));
    }

    /**
     * 根据指定参数查询用户组列表信息
     *
     * @param userGroupDto 相关参数检索信息
     * @param pageSize     页大小
     * @param currentPage  第一页
     * @return 用户组列表
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2021/12/30 14:45
     */
    @Override
    public ServiceResult<PageResponseDTO<UserGroupDTO>> listPage(GroupListRequestDto userGroupDto, Integer pageSize, Integer currentPage) {
        UserGroupDO userGroupDO = new UserGroupDO();
        userGroupDO.setGroupName(userGroupDto.getGroupName());
        userGroupDO.setOrgId(userGroupDto.getOrgId());
        userGroupDO.setGroupLevelId(userGroupDto.getGroupLevelId());

        // 统计数量
        long count = userGroupDao.count(userGroupDO, userGroupDto.getStatuses());
        PageResponseDTO<UserGroupDTO> page = new PageResponseDTO<>();
        if (count <= 0) {
            return ServiceResult.success(page);
        }
        // 查询列表
        List<UserGroupDO> userGroupDos = userGroupDao.listPage(userGroupDO, userGroupDto.getStatuses(), pageSize, currentPage);
        // DOS转DTOS
        List<UserGroupDTO> userGroupDtos = userGroupConvert.dosToDtos(userGroupDos);
        page = new PageResponseDTO<>(userGroupDtos, count, currentPage);
        return ServiceResult.success(page);
    }

    /**
     * 根据分页条件查询相关数据
     *
     * @param userGroupDto 相关参数检索信息
     * @param pageSize     页大小
     * @param currentPage  第一页
     * @return com.bestcem.xm.util.ServiceResult
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/01/25 18:45
     */
    @Override
    public ServiceResult<List<UserGroupDTO>> findByPage(GroupListRequestDto userGroupDto, Integer pageSize, Integer currentPage) {
        UserGroupDO userGroupDO = new UserGroupDO();
        userGroupDO.setGroupName(userGroupDto.getGroupName());
        userGroupDO.setOrgId(userGroupDto.getOrgId());
        // 查询列表
        List<UserGroupDO> userGroupDos = userGroupDao.listPage(userGroupDO, userGroupDto.getStatuses(), pageSize, currentPage);
        // DOS转DTOS
        List<UserGroupDTO> userGroupDtos = userGroupConvert.dosToDtos(userGroupDos);
        return ServiceResult.success(userGroupDtos);
    }

    /**
     * 校验用户组编码是否可用
     *
     * @param groupCode 用户组编码
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Boolean>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2021/12/30 14:45
     */
    @Override
    public ServiceResult<Boolean> checkGroupCode(String groupCode, String orgId) {
        // 参数校验
        if (!ObjectId.isValid(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId为空或者格式不正确");
        }
        if (StringUtils.isBlank(groupCode)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "groupCode不能为空");
        }
        UserGroupDO userGroupDO = new UserGroupDO();
        userGroupDO.setOrgId(orgId);
        userGroupDO.setGroupCode(groupCode);
        UserGroupDO one = userGroupDao.findOne(userGroupDO);
        return ServiceResult.success(Objects.isNull(one));
    }

    /**
     * 用户组失效
     *
     * @param orgId   组织id
     * @param groupId 用户组id
     * @param version 用户组当前版本号
     * @param userId  操作的用户id
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Integer>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2021/12/30 14:34
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<Integer> invalidUserGroup(String orgId, String groupId, Integer version, String userId) {
        // 参数校验
        UserGroupDO param = new UserGroupDO();
        param.setOrgId(orgId);
        param.setGroupId(groupId);
        UserGroupDO userGroupDO = userGroupDao.findOne(param);
        if (Objects.isNull(userGroupDO)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "当前租户下用户组资源不存在！");
        }
        if (!userGroupDO.getVersionId().equals(version)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.DUPLICATE, "当前用户组或子组版本已变更，请重新尝试！");
        }
        if (!userGroupDO.getGroupStatus().equals(UserGroupStatusEnum.ACTIVATED.getStatus())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.STATUS_CHANGED, "当前用户组不处于活动状态！");
        }

        // 1.更新当前组织状态为组织失效
        Boolean result = userGroupDao.invalidUserGroup(groupId, version, userId, UserGroupStatusEnum.ACTIVATED.getStatus(), UserGroupStatusEnum.INACTIVATED.getStatus());
        if (!Boolean.TRUE.equals(result)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "更新失败");
        }

        // 2，获取当前组织下所有有效的子组织id列表，设置为失效
        List<String> validGroupIds = userGroupDao.getChildrenIdsByStatus(groupId, UserGroupStatusEnum.ACTIVATED.getStatus());
        if (CollectionUtils.isNotEmpty(validGroupIds)) {
            // 更新子组织(影藏节点除外，影藏节点会在下面3中异步更新为已删除)状态为失效
            userGroupDao.updateChildrenStatus(validGroupIds, userId, UserGroupStatusEnum.INACTIVATED.getStatus());
        }

        // 发送组织批量失效的消息和组织发生变化的消息
        List<String> invalidGroupIds = new ArrayList<>();
        invalidGroupIds.addAll(validGroupIds);
        invalidGroupIds.add(groupId);
        userMessageSendService.publishGroupInvalidateList(orgId, invalidGroupIds);
        String rootGroupId = "";
        List<String> parentIds = new ArrayList<>();
        if (StringUtils.isNotBlank(userGroupDO.getGroupParentIds())) {
            parentIds = JSON.parseArray(userGroupDO.getGroupParentIds(), String.class);
            if (CollectionUtils.isNotEmpty(parentIds)) {
                rootGroupId = parentIds.get(0);
            }
        }
        userMessageSendService.publishGroupsChange(orgId, rootGroupId);

        // 3.异步处理隐藏节点变为已删除的逻辑
        groupInvalidSyncTask(groupId, userGroupDO.getGroupId(), parentIds, userId, orgId);
        // 4.同步更新组织树的版本号+1
        groupSequenceUtil.incrementVersion(orgId);
        return ServiceResult.success(version + 1);
    }

    /**
     * 移除或者添加某个用户组下的用户信息
     *
     * @param orgId   组织id
     * @param groupId 用户组id
     * @param userIds 添加的用户id列表
     * @param type    操作类型
     * @param userId  操作的用户id
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Integer>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2021/12/30 14:37
     */
    @Override
    public ServiceResult<Integer> handleUsers(String orgId, String groupId, List<String> userIds, Integer type, String userId) {
        // 参数校验
        UserGroupOperateUserEnum operateType = UserGroupOperateUserEnum.getByType(type);
        if (null == operateType) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "操作类型不正确");
        }
        UserGroupDO temp = userGroupDao.findOne(new UserGroupDO(groupId, UserGroupStatusEnum.ACTIVATED.getStatus(), orgId));
        if (Objects.isNull(temp)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到该有效状态的用户组");
        }
        // 查询当前组织的根组织id
        UserGroupDO rootGroup = userGroupDao.getRootGroupByOrgId(orgId);
        return userUserGroupService.batchOperateUser(groupId, rootGroup.getGroupId(), operateType, userIds, userId);
    }

    /**
     * 查询某个组织的根组织信息
     *
     * @param orgId 组织id
     * @return com.bestcem.xm.util.ServiceResult<com.bestcem.xm.user.group.service.dto.group.UserGroupDTO>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2021/12/30 16:54
     */
    @Override
    public ServiceResult<UserGroupDTO> getRootGroupByOrgId(String orgId) {
        // 参数校验
        if (!ObjectId.isValid(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId为空或者格式不正确");
        }
        UserGroupDO userGroupDO = userGroupDao.getRootGroupByOrgId(orgId);
        UserGroupDTO userGroupDTO = userGroupConvert.doToDto(userGroupDO);
        setPhoneEmailAdminName(Collections.singletonList(userGroupDTO));
        return ServiceResult.success(userGroupDTO);
    }

    /**
     * 根据组织id查询用户组列表
     *
     * @param orgId 组织id
     * @return com.bestcem.xm.util.ServiceResult<java.util.List < com.bestcem.xm.user.group.service.dto.group.UserGroupDTO>>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/01/04 11:47
     */
    @Override
    public ServiceResult<List<UserGroupDTO>> listByOrgId(String orgId) {
        UserGroupDO userGroupDO = new UserGroupDO();
        userGroupDO.setOrgId(orgId);
        List<UserGroupDO> userGroupDOS = userGroupDao.listByCondition(userGroupDO);
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDOS));
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> listByCondition(UserGroupDTO userGroupDTO) {
        // 转换参数
        UserGroupDO userGroupDO = userGroupConvert.dtoToDo(userGroupDTO);
        // 校验参数
        if (StringUtils.isBlank(userGroupDO.getOrgId())) {
            return ServiceResult.fail("机构id参数不能为空");
        }
        // 查询并返回结果
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDao.listByCondition(userGroupDO)));
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> listBySelective(UserGroupDTO userGroupDTO) {
        // 校验参数
        if (StringUtils.isBlank(userGroupDTO.getGroupLevelId())) {
            return ServiceResult.fail("层级id参数不能为空");
        }
        // 转换参数
        UserGroupDO userGroupDO = userGroupConvert.dtoToDo(userGroupDTO);
        // 查询并返回结果
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDao.listByCondition(userGroupDO)));
    }

    /**
     * 根据用户组id查询用户组信息
     *
     * @param groupId 用户组id
     * @return com.bestcem.xm.util.ServiceResult<com.bestcem.xm.user.group.service.dto.group.UserGroupDTO>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/01/24 10:36
     */
    @Override
    public ServiceResult<UserGroupDTO> getById(String groupId) {
        // 参数校验
        if (!ObjectId.isValid(groupId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "用户组id为空或者格式不正确");
        }
        UserGroupDO userGroupDO = userGroupDao.getById(groupId);
        if (Objects.isNull(userGroupDO)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到数据信息");
        }
        UserGroupDTO userGroupDTO = userGroupConvert.doToDto(userGroupDO);
        // 处理手机号、邮件、管理员姓名
        setPhoneEmailAdminName(Collections.singletonList(userGroupDTO));
        return ServiceResult.success(userGroupDTO);
    }

    /**
     * 获取当前层级的父级
     *
     * @param groupId
     * @return
     */
    @Override
    public ServiceResult<List<String>> getGroupAncestorsByGroupId(String groupId) {
        UserGroupDO group = userGroupDao.getById(groupId);

        ArrayList<String> ancestorsIdList = new ArrayList<>();
        while (StringUtils.isNotBlank(group.getGroupParentId())) {
            String groupParent = userCacheUtil.get(UserGroupConstant.GROUP_PARENT + group.getGroupId());
            if (StringUtils.isBlank(groupParent)) {
                UserGroupDO g = userGroupDao.getById(group.getGroupParentId());
                if (Objects.nonNull(g)) {
                    ancestorsIdList.add(g.getGroupId());

                    HashMap<String, String> map = new HashMap<>();
                    map.put("id", g.getGroupId());
                    map.put("parentID", StringUtils.isNotBlank(g.getGroupParentId()) ? g.getGroupParentId() : "");
                    userCacheUtil.setEx(UserGroupConstant.GROUP_PARENT + group.getGroupId(), map, 10);

                    group = g;
                }
            } else {
                JSONObject jsonObject = JSON.parseObject(groupParent);
                ancestorsIdList.add(jsonObject.get("id").toString());
                UserGroupDO parentGroup = new UserGroupDO();
                parentGroup.setGroupId(jsonObject.get("id").toString());
                parentGroup.setGroupParentId(jsonObject.get("parentID").toString());
                group = parentGroup;
            }
        }
        return ServiceResult.success(ancestorsIdList);
    }

    /**
     * 根据公司id和组织编码查询用户组信息
     *
     * @param orgId     组织Id
     * @param groupCode 组织编码
     * @return UserGroupDTO
     * @author yanjishuo <jishuo.yan@idiaoyan.cn>
     * @date 2022/01/24 10:36
     */
    @Override
    public ServiceResult<UserGroupDTO> getByOrgIdAndGroupCode(String orgId, String groupCode) {
        //参数校验
        if (!ObjectId.isValid(orgId) || StringUtils.isBlank(groupCode)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "用户组id为空或者格式不正确");
        }
        UserGroupDO param = new UserGroupDO();
        param.setOrgId(orgId);
        param.setGroupCode(groupCode);
        UserGroupDO userGroup = userGroupDao.findOne(param);
        if (Objects.isNull(userGroup)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到数据信息");
        }
        UserGroupDTO userGroupDTO = userGroupConvert.doToDto(userGroup);
        // 处理手机号、邮件、管理员姓名
        setPhoneEmailAdminName(Collections.singletonList(userGroupDTO));
        return ServiceResult.success(userGroupDTO);
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> getByOrgIdAndGroupCodes(String orgId, Set<String> groupCodes) {
        //参数校验
        if (!ObjectId.isValid(orgId) || CollectionUtils.isEmpty(groupCodes)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "用户组id为空或者格式不正确或者组织编码为空");
        }
        List<UserGroupDO> userGroupDOs = userGroupDao.getByOrgIdAndGroupCodes(orgId, groupCodes);
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDOs));
    }

    /**
     * 根据租户id和组织id列表查询组织信息列表
     *
     * @param orgId        租户id
     * @param groupIdsList 组织id列表
     * @return java.util.List<com.bestcem.xm.user.group.service.dto.group.UserGroupDTO>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/01/24 13:51
     */
    @Override
    public ServiceResult<List<UserGroupDTO>> getGroupsByOrgIdAndGroupIds(String orgId, List<String> groupIdsList) {
        // 参数校验
        if (ObjectUtil.isEmpty(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "租户id为空或者格式不正确");
        }
        if (ObjectUtil.isAllEmpty(groupIdsList)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织id列表为空或者格式不正确");
        }

        List<UserGroupDO> userGroupDOs = userGroupDao.getGroupsByOrgIdAndGroupIds(orgId, groupIdsList);
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDOs));
    }

    /**
     * 批量插入组织信息
     *
     * @param userGroups 组织信息列表
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Boolean>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/01/26 16:39
     */
    @Override
    public ServiceResult<Boolean> insertBatch(List<UserGroupDTO> userGroups) {
        // 参数校验
        if (CollectionUtils.isEmpty(userGroups)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织信息列表为空");
        }
        userGroupDao.insertBatch(userGroupConvert.dtosToDos(userGroups));
        return ServiceResult.success(true);
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> getChildrenByGroupIds(List<String> groupIdsList) {
        // 递归查询指定用户组列表下的所有子用户组
        if (CollectionUtils.isEmpty(groupIdsList)) {
            return ServiceResult.success(new ArrayList<>());
        }

        List<UserGroupDO> userGroupDOS = userGroupDao.listByGroupIds(groupIdsList);

        List<String> idList = new ArrayList<>();
        for (UserGroupDO groupDO : userGroupDOS) {
            if (groupDO.getHaveChildrenFlag() == 0) {
                continue;
            }
            List<UserGroupDO> childrenListByGroupId = userGroupDao.getChildrenListByGroupId(groupDO.getGroupId());
            idList = childrenListByGroupId.stream().map(UserGroupDO::getGroupId).collect(Collectors.toList());
        }

        return this.getChildrenByGroupIds(idList);
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> getSelfAndChildrenByGroupId(String groupId, boolean includeInactive) {
        // 获取所有子用户组信息
        List<UserGroupDO> listByGroupId = userGroupDao.getChildrenListByRootGroupId(groupId, includeInactive);
        // 获取指定用户组信息
        UserGroupDO rootGroup = userGroupDao.getById(groupId);
        listByGroupId.add(rootGroup);
        return ServiceResult.success(userGroupConvert.dosToDtos(listByGroupId));
    }

    @Override
    public ServiceResult<Integer> getSelfAndChildrenCountByGroupId(String groupId, boolean includeInactive) {
        return ServiceResult.success(userGroupDao.getSelfAndChildrenCountByGroupId(groupId, includeInactive));
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> userGroupListByOrgId(OrgStatusPageParam param) {
        // 参数校验
        if (!ObjectId.isValid(param.getOrgId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId为空或者格式不正确");
        }
        List<UserGroupDO> dos = userGroupDao.getListByOrgId(param);
        List<UserGroupDTO> dtos = userGroupConvert.dosToDtos(dos);
        setPhoneEmailAdminName(dtos);
        return ServiceResult.success(dtos);
    }

    /**
     * 设置手机号，邮箱，管理员姓名
     *
     * @param dtos 组织列表信息
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/04/28 18:07
     */
    private void setPhoneEmailAdminName(List<UserGroupDTO> dtos) {
        List<String> idList = dtos.stream().filter(c -> Objects.nonNull(c) && StringUtils.isNotBlank(c.getAdminId())).map(UserGroupDTO::getAdminId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(idList)) {
            return;
        }

        ServiceResult<List<UserDTO>> listServiceResult = userService.selectByIds(idList);
        List<UserDTO> userList = listServiceResult.getData();
        Map<String, UserDTO> userDTOMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(userList)) {
            userDTOMap = listServiceResult.getData().stream().collect(Collectors.toMap(UserDTO::getUserId, Function.identity()));
        }
        for (UserGroupDTO dto : dtos) {
            if (StringUtils.isBlank(dto.getAdminId()) || !userDTOMap.containsKey(dto.getAdminId())) {
                dto.setPhone("");
                dto.setEmail("");
                dto.setAdminName("");
            } else {
                UserDTO userDTO = userDTOMap.get(dto.getAdminId());
                dto.setPhone(Objects.nonNull(userDTO.getPhone()) ? userDTO.getPhone() : "");
                dto.setEmail(Objects.nonNull(userDTO.getEmail()) ? userDTO.getEmail() : "");
                dto.setAdminName(Objects.nonNull(userDTO.getName()) ? userDTO.getName() : "");
            }
        }
    }

    @Override
    public ServiceResult<Long> userGroupCountByOrgId(OrgStatusPageParam param) {
        // 参数校验
        if (!ObjectId.isValid(param.getOrgId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId为空或者格式不正确");
        }
        Integer count = userGroupDao.userGroupCountByOrgId(param);
        return ServiceResult.success(count.longValue());
    }

    @Override
    public ServiceResult<PageResponseDTO<UserGroupDTO>> userGroupListByParentGroupId(OrgStatusPageParam param) {
        // 参数校验
        if (!ObjectId.isValid(param.getParentGroupId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "用户组id为空或者格式不正确");
        }
        UserGroupDO parentGroup = userGroupDao.getById(param.getParentGroupId());
        if (Objects.isNull(parentGroup) || Objects.isNull(parentGroup.getGroupLevelId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "用户组不存在 id:" + param.getParentGroupId());
        }

        // 查询父组织层级信息
        ServiceResult<UserGroupLevelDTO> levelService = userGroupLevelService.getById(parentGroup.getGroupLevelId());
        UserGroupLevelDTO level = levelService.getData();
        if (!levelService.isSuccess() || Objects.isNull(level)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "层级不存在 id:" + parentGroup.getGroupLevelId());
        }

        PageResponseDTO<UserGroupDTO> page = new PageResponseDTO<>();
        if (Objects.isNull(level.getLevelChildrenId())) {
            page.setTotal(0L);
            return ServiceResult.success(page);
        }

        List<Integer> statusList = param.getStatusList();
        if (CollectionUtils.isEmpty(statusList)) {
            statusList.add(GROUP_STATUS_ACTIVATED.getIndex());
            statusList.add(GroupStatusEnum.GROUP_STATUS_INACTIVATED.getIndex());
            statusList.add(GroupStatusEnum.GROUP_STATUS_HIDDEN.getIndex());
            statusList.add(GroupStatusEnum.GROUP_STATUS_DELETED.getIndex());
        }

        // 统计数量
        long count = userGroupDao.countChildrenNum(parentGroup.getGroupId(), level.getLevelChildrenId(), statusList);
        if (count == 0) {
            page.setTotal(0L);
            return ServiceResult.success(page);
        }

        // 分页查询列表
        PageParam pageParam = param.getPageParam();
        List<UserGroupDO> dos = userGroupDao.listPageChildren(parentGroup.getGroupId(), level.getLevelChildrenId(), statusList, pageParam.getSize(), pageParam.getPage());
        List<UserGroupDTO> groupDTOS = userGroupConvert.dosToDtos(dos);
        setPhoneEmailAdminName(groupDTOS);
        page = new PageResponseDTO<>(groupDTOS, count, pageParam.getPage());
        return ServiceResult.success(page);
    }

    @Override
    public ServiceResult<Integer> userGroupCountByParentGroupId(OrgStatusPageParam param) {
        // 参数校验
        if (!ObjectId.isValid(param.getParentGroupId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId为空或者格式不正确");
        }
        int count = userGroupDao.userGroupCountByParentGroupId(param);
        return ServiceResult.success(count);
    }

    /**
     * 根据用户组id列表获取指定层级上的子用户组数量
     *
     * @param groupLevelId 层级id
     * @param groupIdsList 组织id列表
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Long>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/02/07 09:51
     */
    @Override
    public ServiceResult<Long> countSubRelate(String groupLevelId, List<String> groupIdsList) {
        // 参数校验
        if (!ObjectId.isValid(groupLevelId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "层级id不能为空或格式不正确");
        }
        if (ObjectUtil.isAllEmpty(groupIdsList)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织id列表不能为空或格式不正确");
        }

        long count = userGroupDao.countSubRelate(groupLevelId, groupIdsList);
        return ServiceResult.success(count);
    }

    /**
     * 根据用户组id列表分页获取指定层级上的子用户列表
     *
     * @param groupLevelId 层级id
     * @param groupIdsList 组织id列表
     * @param pageSize     每页大小
     * @param currentPage  第几页
     * @return com.bestcem.xm.util.ServiceResult<java.util.List < com.bestcem.xm.user.group.service.dto.group.UserGroupDTO>>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/02/07 09:56
     */
    @Override
    public ServiceResult<List<UserGroupDTO>> listPageSubRelate(String groupLevelId, List<String> groupIdsList, Integer pageSize, Integer currentPage) {
        // 参数校验
        if (!ObjectId.isValid(groupLevelId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "层级id不能为空或格式不正确");
        }
        if (ObjectUtil.isAllEmpty(groupIdsList)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织id列表不能为空或格式不正确");
        }
        if (null == pageSize || pageSize < 1) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "pageSize不能小于1");
        }
        if (null == currentPage || currentPage < 1) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "currentPage不能小于1");
        }

        List<UserGroupDO> userGroupDOs = userGroupDao.listPageSubRelate(groupLevelId, groupIdsList, pageSize, currentPage);
        // 将do转成dto
        List<UserGroupDTO> userGroupDTOS = userGroupConvert.dosToDtos(userGroupDOs);
        return ServiceResult.success(userGroupDTOS);
    }

    @Override
    public ServiceResult<PageResponseDTO<UserGroupResumeDTO>> listPages(GroupsListRequestDTO dto, String orgId, String userId, boolean isAdmin, Integer page, Integer size) {
        // 参数校验
        if (StringUtils.isBlank(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId不存在");
        }
        PageResponseDTO<UserGroupResumeDTO> pageDTO = new PageResponseDTO<>(new ArrayList<>(), 0L, page);

        // 设置搜索条件参数
        SearchDO searchDO = new SearchDO();
        searchDO.setOrgId(orgId);
        if (StringUtils.isNotBlank(dto.getSearch())) {
            searchDO.setSearch(dto.getSearch());
        }
        if (Objects.nonNull(dto.getGroupStatus())) {
            searchDO.setStatus(dto.getGroupStatus());
        }

        List<String> parentGroupLevelIds = new ArrayList<>();
        // 获取当前公司所有组织层级
        List<UserGroupLevelDO> allGroupLevels = userGroupLevelDao.getGroupLevelsByOrgId(orgId);
        if (CollectionUtils.isNotEmpty(allGroupLevels) && StringUtils.isNotBlank(dto.getLowestLevelId())) {
            // 获取当前所属层级
            UserGroupLevelDO groupLevel = allGroupLevels.stream().filter(g -> g.getGroupLevelId().equals(dto.getLowestLevelId())).findFirst().orElse(null);
            if (Objects.nonNull(groupLevel)) {
                // 获取上级组织层级id
                parentGroupLevelIds = allGroupLevels.stream().filter(r -> r.getLevelNum() < groupLevel.getLevelNum()).map(UserGroupLevelDO::getGroupLevelId).collect(Collectors.toList());
                // 如果包括当前层级
                if (Objects.nonNull(dto.getIncludeLowestLevelId()) && BooleanStatusEnum.YES.getStatus().equals(dto.getIncludeLowestLevelId())) {
                    parentGroupLevelIds = allGroupLevels.stream().filter(r -> r.getLevelNum() <= groupLevel.getLevelNum()).map(UserGroupLevelDO::getGroupLevelId).collect(Collectors.toList());
                }
            }
        }

        // 只返回用户所属组织的一串层级(往上到顶和往下到底)，其它层级不返回；超管和系统管理员展示所有组织
        List<UserGroupDO> userGroupDOS = userGroupDao.listGroupByUserIdAndStatus(userId, UserGroupStatusEnum.ACTIVATED.getStatus());
        if (userGroupDOS.isEmpty() && !isAdmin) {
            return ServiceResult.success(pageDTO);
        }
        Set<String> parentIds = new HashSet<>();
        Set<String> currentIds = new HashSet<>();
        if (!isAdmin) {
            for (UserGroupDO userGroupDO : userGroupDOS) {
                currentIds.add(userGroupDO.getGroupId());
                parentIds.add(userGroupDO.getGroupId());
                if (userGroupDO.getGroupParentIds() != null) {
                    List<String> parentGroupIds = JSON.parseArray(userGroupDO.getGroupParentIds(), String.class);
                    parentIds.addAll(parentGroupIds);
                }
            }
        }

        // 统计数量
        long count = userGroupDao.countSearch(searchDO, parentGroupLevelIds, parentIds, currentIds);
        if (count <= 0) {
            return ServiceResult.success(pageDTO);
        }

        /*
         * 判断是否传递父组织id，且父组织的状态是否满足置顶【组织未失效】
         * 如果满足置顶，第一页查询size-1即可，后续的页继续查询size
         * 同事如果满足置顶，在做分页查询时，需要过滤掉groupId不等于groupParentId，否则可能会出现展示两次的问题
         */
        boolean toppingFlag = false;
        UserGroupDO parentGroup = null;
        if (StringUtils.isNotBlank(dto.getGroupParentId())) {
            parentGroup = userGroupDao.getById(dto.getGroupParentId());
            // 上级组织未失效，才会置顶
            if (Objects.nonNull(parentGroup) && UserGroupStatusEnum.ACTIVATED.getStatus().equals(searchDO.getStatus()) && parentGroup.getGroupStatus().equals(UserGroupStatusEnum.ACTIVATED.getStatus()) && parentGroup.getOrgId().equals(orgId)) {
                toppingFlag = true;
                searchDO.setGroupParentId(dto.getGroupParentId());
            }
        }

        int offset = 0;
        int pageSize = size;
        // 如果满足置顶的条件
        if (toppingFlag) {
            // 查询父组织第一页页数减少1
            if (page.equals(1)) {
                pageSize--;
            } else {
                // 后续页，由于第一页置少查询了一条，则后面要往前面诺一条
                offset = (page - 1) * size - 1;
            }
        } else {
            offset = (page - 1) * size;
        }

        // 分页查询列表
        List<UserGroupDO> userGroupDos = userGroupDao.listPages(searchDO, parentGroupLevelIds, parentIds, currentIds, offset, pageSize);
        // 如果第一页置顶，则需要补充置顶的置顶信息
        if (toppingFlag && page.equals(1)) {
            userGroupDos.add(0, parentGroup);
        }
        if (CollectionUtils.isEmpty(userGroupDos)) {
            return ServiceResult.success(pageDTO);
        }

        // UserGroupDos转换成UserGroupResumeDTOs
        List<UserGroupResumeDTO> data = userGroupConvert.dosToResumeDtos(userGroupDos);

        // 查询groupLevelName
        Map<String, String> levelNameMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(allGroupLevels)) {
            levelNameMap = allGroupLevels.stream().collect(Collectors.toMap(UserGroupLevelDO::getGroupLevelId, UserGroupLevelDO::getGroupLevelName, (c1, c2) -> c2));
        }

        // 查询groupParentName
        Map<String, String> groupParentNameMap = new HashMap<>();
        Map<String, Integer> groupParentStatusMap = new HashMap<>();
        // 对groupParentIds进行去重
        Set<String> groupParentIds = data.stream().map(UserGroupResumeDTO::getGroupParentId).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        List<UserGroupDO> parentGroups = userGroupDao.getByGroupIds(new ArrayList<>(groupParentIds));
        if (CollectionUtils.isNotEmpty(parentGroups)) {
            groupParentNameMap = parentGroups.stream().collect(Collectors.toMap(UserGroupDO::getGroupId, UserGroupDO::getGroupName, (c1, c2) -> c2));
            groupParentStatusMap = parentGroups.stream().collect(Collectors.toMap(UserGroupDO::getGroupId, UserGroupDO::getGroupStatus, (c1, c2) -> c2));
        }

        for (UserGroupResumeDTO resumeDTO : data) {
            // 设置groupLevelName
            resumeDTO.setGroupLevelName(levelNameMap.get(resumeDTO.getGroupLevelId()));
            // 设置groupParentName
            resumeDTO.setGroupParentName(groupParentNameMap.get(resumeDTO.getGroupParentId()));
            // 设置groupParentStatus
            resumeDTO.setGroupParentStatus(groupParentStatusMap.get(resumeDTO.getGroupParentId()));
        }
        pageDTO = new PageResponseDTO<>(data, count, page);
        return ServiceResult.success(pageDTO);
    }

    /**
     * 根据组织id查询当前组织及其所有的父组织列表信息
     *
     * @param groupId 当前的组织id
     * @return java.util.List<com.bestcem.xm.user.group.service.dto.group.UserGroupDTO>
     * @author yanjishuo <jishuo.yan@idiaoyan.cn>
     * @date 2022/01/24 15:50
     */
    @Override
    public ServiceResult<List<UserGroupDTO>> getSelfAndParents(String groupId) {
        // 参数校验
        if (!ObjectId.isValid(groupId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织Id为空或者格式不对");
        }
        // 创建当前和所有父用户组信息列表
        List<UserGroupDO> userGroupDOS = new ArrayList<>();
        // 获取当前用户组信息
        UserGroupDO groupDO = userGroupDao.getById(groupId);
        if (Objects.isNull(groupDO)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NO_DATA, "数据不存在");
        }
        // 获取父节点id列表
        String groupParentIds = groupDO.getGroupParentIds();
        if (StringUtils.isNotBlank(groupParentIds)) {
            List<String> parentIds = JSON.parseArray(groupParentIds, String.class);
            // 获取所有父组织信息列表
            List<UserGroupDO> parentGroups = userGroupDao.listByGroupIds(parentIds);
            if (CollectionUtils.isNotEmpty(parentGroups)) {
                Map<String, UserGroupDO> map = parentGroups.stream().collect(Collectors.toMap(UserGroupDO::getGroupId, u -> u, (u1, u2) -> u1));
                // 处理排序，按照指定的的parentIds的顺序去排序
                int index = 0;
                for (String parentId : parentIds) {
                    if (map.containsKey(parentId)) {
                        userGroupDOS.add(index, map.get(parentId));
                        index++;
                    }
                }
            }
        }
        userGroupDOS.add(groupDO);
        List<UserGroupDTO> userGroupDTOS = userGroupConvert.dosToDtos(userGroupDOS);
        return ServiceResult.success(userGroupDTOS);
    }

    /**
     * 通过根组织id获取组织树的版本号
     *
     * @param rootGroupId 当前根组织id
     * @return versionId 组织树的版本号
     * @author yanjishuo <jishuo.yan@idiaoyan.cn>
     * @date 2022/01/25 11:00
     */
    @Override
    public ServiceResult<Integer> getGroupTreeVersion(String rootGroupId) {
        if (!ObjectId.isValid(rootGroupId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "根组织Id为空或者格式不对");
        }
        UserGroupDO userGroup = userGroupDao.getById(rootGroupId);
        if (Objects.isNull(userGroup)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应的根组织信息");
        }

        int version = groupSequenceUtil.getVersion(userGroup.getOrgId());
        return ServiceResult.success(version);
    }

    /**
     * 根据user_id获取用户组id列表
     *
     * @param userId 用户Id
     * @return 用户组Id列表
     * @author yanjishuo <jishuo.yan@idiaoyan.cn>
     * @date 2022/01/24 11:20
     */
    @Override
    public ServiceResult<HashSet<String>> getGroupIdsByUserId(String userId) {
        // 参数校验
        if (!ObjectId.isValid(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "层级id不能为空或格式不正确");
        }
        // groupParentIds中的元素可能会重复，所以使用hashset类型
        HashSet<String> allGroupIds = new HashSet<>();
        // 1. 根据userId查询userUserGroup中关联的groupId列表
        // 2. 根据groupId列表查询所有有效状态的组织信息
        // 2.5 一二步连表查询
        List<UserGroupDO> userGroupDOS = userGroupDao.listGroupByUserId(userId);
        // 3. 获取第二步中的所有父组织id列表
        for (UserGroupDO userGroupDO : userGroupDOS) {
            if (!userGroupDO.getGroupStatus().equals(UserGroupStatusEnum.ACTIVATED.getStatus())) {
                continue;
            }
            String groupId = userGroupDO.getGroupId();
            allGroupIds.add(groupId);
            String groupParentIds = userGroupDO.getGroupParentIds();
            if (StringUtils.isNotBlank(groupParentIds)) {
                allGroupIds.addAll(JSON.parseArray(groupParentIds, String.class));
            }
        }
        return ServiceResult.success(allGroupIds);
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> getGroupsByOrgId(String orgId, ArrayList<SortParam> sortList, PageParam page) {
        // 参数校验
        if (!ObjectId.isValid(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "orgId为空或者格式不正确");
        }

        // 按层级从小到大排序
        List<UserGroupLevelDO> levelsByOrgId = userGroupLevelDao.getGroupLevelsByOrgId(orgId);
        if (CollectionUtils.isEmpty(levelsByOrgId)) {
            return ServiceResult.fail("当前租户下不存在门店");
        }
        // 获取最末层级
        UserGroupLevelDO userGroupLevelDO = levelsByOrgId.get(levelsByOrgId.size() - 1);

        UserGroupDO userGroupDO = new UserGroupDO();
        userGroupDO.setOrgId(orgId);
        userGroupDO.setGroupLevelId(userGroupLevelDO.getGroupLevelId());

        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(UserGroupStatusEnum.ACTIVATED.getStatus());

        List<UserGroupDO> userGroupDOS = userGroupDao.listByConditionAndSort(userGroupDO, statusList, sortList, page);
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDOS));
    }

    @Override
    public ServiceResult<Integer> getGroupCountByOrgId(String orgId) {
        // 根据orgId查询最末层级
        List<UserGroupLevelDO> levelsByOrgId = userGroupLevelDao.getGroupLevelsByOrgId(orgId);
        UserGroupLevelDO userGroupLevelDO = levelsByOrgId.get(levelsByOrgId.size() - 1);

        UserGroupDO userGroupDO = new UserGroupDO();
        userGroupDO.setOrgId(orgId);
        userGroupDO.setGroupLevelId(userGroupLevelDO.getGroupLevelId());

        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(UserGroupStatusEnum.ACTIVATED.getStatus());

        int count = userGroupDao.countByConditionAndSort(userGroupDO, statusList);

        return ServiceResult.success(count);
    }

    /**
     * 搜索用户组列表
     *
     * @param param:
     * @return
     * @author Linked <zhijian.lin@idiaoyan.com>
     * @date 2022/1/24 17:32
     */
    @Override
    public PageResponseDTO<UserGroupDTO> listUserGroups(UserGroupListParam param) {

        ListUserGroupParamDO paramDO = new ListUserGroupParamDO();
        BeanUtils.copyProperties(param, paramDO);

        // 分页条件
        paramDO.setStart((param.getPageParam().getPage() - 1) * param.getPageParam().getSize());
        paramDO.setSize(param.getPageParam().getSize());

        Long count = userGroupDao.listUserGroupCount(paramDO);
        if (count == 0L) {
            return new PageResponseDTO<>(new ArrayList<>(), count, param.getPageParam().getOffset());
        }
        List<UserGroupDO> groupDOList = userGroupDao.listUserGroup(paramDO);
        return new PageResponseDTO<>(userGroupConvert.dosToDtos(groupDOList), count, param.getPageParam().getOffset());
    }

    /**
     * 根据用户组id列表获取指定层级上关联的用户组信息
     * rpc_mysql/user/server.py:289
     *
     * @param param:
     * @return
     * @author Linked <zhijian.lin@idiaoyan.com>
     * @date 2022/1/25 16:52
     */
    @Override
    public ListRelateGroupsDTO listRelateGroups(ListRelateGroupsParam param) {
        ListRelateGroupsDTO relateGroupsDTO = new ListRelateGroupsDTO();
        PageParam pageParam = new PageParam(param.getPageParam().getOffset(), param.getPageParam().getSize());
        // 获取层级
        UserGroupLevelDO levelDO = userGroupLevelDao.getById(param.getGroupLevelId());
        Integer levelNum = levelDO.getLevelNum();
        // 组织列表
        List<UserGroupDO> groupList = userGroupDao.listByGroupIds(param.getGroupIds());
        // group_ids中在level_id之上的group_id,python是group元素 这里用id方便分页
        Set<String> upperIds = new HashSet<>();
        // group_ids中在level_id之下的组对应level_id上的祖先节点id,python是group元素 这里用id方便分页
        List<String> relatedIds = new ArrayList<>();

        List<UserGroupDO> relatedList = new ArrayList<>();
        Map<String, UserGroupDTO> groupMap = new HashMap<>();
        ServiceResult<List<UserGroupDTO>> listServiceResult = listByOrgId(levelDO.getOrgId());
        List<UserGroupDTO> data = listServiceResult.getData();
        for (UserGroupDTO userGroupDTO : data) {
            groupMap.put(userGroupDTO.getGroupId(), userGroupDTO);
        }

        for (UserGroupDO userGroup : groupList) {
            List<String> ancestors = getGroupAncestorsByGroupIdGroupData(userGroup.getGroupId(), groupMap);
            if (ancestors.size() == levelNum) {
                // 指定组织的与指定层级同级的情况
                relatedList.add(userGroup);
            } else if (ancestors.size() > levelNum) {
                // 指定组织在指定层级的下级的情况
                relatedIds.add(ancestors.get((ancestors.size() - levelDO.getLevelNum()) - 1));
            } else {
                // 指定组织在指定层级的上级的情况
                upperIds.add(userGroup.getGroupId());
            }
        }
        // 指定组织的与指定层级同级
        List<String> groupIds = relatedList.stream().map(UserGroupDO::getGroupId).collect(Collectors.toList());
        relatedIds.addAll(groupIds);

        List<String> groupIdsByLevelId = userGroupDao.listByLevelIds(Collections.singletonList(param.getGroupLevelId()));
        for (String groupId : groupIdsByLevelId) {
            List<String> ancestors = getGroupAncestorsByGroupIdGroupData(groupId, groupMap);
            Set<String> ancestorsSet = new HashSet<>(ancestors);
            if (ancestorsSet.removeAll(upperIds)) {
                relatedIds.add(groupId);
            }
        }

        // 所有的子组织id
        List<GroupBaseDTO> groups = userGroupDao.listRelateGroups(relatedIds, pageParam.getOffset(), pageParam.getSize());
        Integer count = userGroupDao.listRelateGroupsCount(relatedIds);
        relateGroupsDTO.setGroups(groups);
        relateGroupsDTO.setTotal(count);
        return relateGroupsDTO;
    }

    /**
     * 获取父组织id 从近到远排序
     *
     * @param groupId
     * @param groupDTOMap
     * @return java.util.List<java.lang.String>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/08/01 10:58
     */
    private List<String> getGroupAncestorsByGroupIdGroupData(String groupId, Map<String, UserGroupDTO> groupDTOMap) {
        UserGroupDTO userGroupDTO = groupDTOMap.get(groupId);
        List<String> ancestorsList = new ArrayList<>();
        while (StringUtils.isNotBlank(userGroupDTO.getGroupParentId())) {
            UserGroupDTO g = groupDTOMap.get(userGroupDTO.getGroupParentId());
            if (Objects.isNull(g)) {
                break;
            }
            ancestorsList.add(g.getGroupId());
            userGroupDTO = g;
        }
        return ancestorsList;
    }

    /**
     * 获取所有的子组织id
     *
     * @param orgId        公司id
     * @param groupIdList: 组织id列表
     * @return
     * @author Linked <zhijian.lin@idiaoyan.com>
     * @date 2022/1/25 16:52
     */
    public List<String> getAllSubGroupIds(String orgId, List<String> groupIdList) {
        Set<String> allSubGroupIds = new HashSet<>();
        for (String groupId : groupIdList) {
            List<String> subGroupIds = userGroupDao.getSubGroupIds(orgId, groupId);
            allSubGroupIds.addAll(subGroupIds);
        }
        return new ArrayList<>(allSubGroupIds);
    }

    @Override
    public ListSubGroupsDTO getSubGroupsByGroupIds(ListSubGroupsByGroupIdsParam param) {
        ListSubGroupsDTO subGroupsDTO = new ListSubGroupsDTO();
        List<String> groupIds = param.getGroupIds();

        List<GroupBaseDTO> subGroupList = new ArrayList<>();
        Long subGroupCount = userGroupDao.getSubGroupCount(groupIds);
        if (subGroupCount == 0L) {
            subGroupsDTO.setGroups(subGroupList);
        } else {
            subGroupList = userGroupDao.getSubGroupByPage(groupIds, param.getPageParam().getOffset(), param.getPageParam().getSize());
        }
        subGroupsDTO.setGroups(subGroupList);
        subGroupsDTO.setTotal(subGroupCount);
        return subGroupsDTO;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ServiceResult<GroupInfoDTO> resumeUserGroup(UserGroupDTO userGroupDTO) {
        RLock lock = redisService.getLock(GROUP_RESUME_LOCK + userGroupDTO.getOrgId());
        if (!lock.tryLock()) {
            return ServiceResult.fail("您的操作太频繁，请稍等片刻");
        }
        try {
            // 查询公司信息
            OrganizationDTO organizationDTO = organizationService.selectByPrimaryKey(userGroupDTO.getOrgId()).getData();
            if (organizationDTO == null) {
                return ServiceResult.fail("未查询到对应的公司信息");
            }
            if (StringUtils.isBlank(organizationDTO.getRootGroupId())) {
                return ServiceResult.fail("公司根组织信息为空");
            }

            // 通过group_id查询组织, 并校验组织信息
            ServiceResult<UserGroupDTO> groupResult = checkAndGetGroupByResume(userGroupDTO);
            if (!groupResult.isSuccess()) {
                return ServiceResult.fail(groupResult.getMsg());
            }

            // 判断是否存在组织编码重复, 如果存在则无法恢复改组织
            ServiceResult<GroupInfoDTO> checkRepetCodeRt = checkRepetCodeByResume(groupResult.getData());
            if (!checkRepetCodeRt.isSuccess()) {
                return ServiceResult.fail(checkRepetCodeRt.getData(), checkRepetCodeRt.getMsg(), checkRepetCodeRt.getErrorCode());
            }

            // 通过group_parent_id查询组织, 并校验组织信息
            ServiceResult<UserGroupDTO> parentGroupResult = checkAndGetParentGroupByResume(userGroupDTO);
            if (!parentGroupResult.isSuccess()) {
                return ServiceResult.fail(parentGroupResult.getMsg());
            }

            // 通过group_level_id查询层级, 并校验层级信息
            ServiceResult<Map<String, Integer>> levelsResult = checkAndGetLevelsByResume(userGroupDTO.getOrgId());
            if (!levelsResult.isSuccess()) {
                return ServiceResult.fail(levelsResult.getMsg());
            }

            UserGroupDTO parentGroupDTO = parentGroupResult.getData();
            // 设置组织的更新参数
            UserGroupDTO groupDTO = groupResult.getData();
            Date now = DataBaseUtil.getDate();
            groupDTO.setUpdateTime(now);
            groupDTO.setOperatorId(userGroupDTO.getOperatorId());
            groupDTO.setGroupLevelId(userGroupDTO.getGroupLevelId());
            groupDTO.setGroupStatus(UserGroupStatusEnum.ACTIVATED.getStatus());
            //groupDTO.setVersionId(userGroupDTO.getVersionId() + 1);
            groupDTO.setHaveChildrenFlag(HaveChildrenFlagEnum.NOT_HAVE.getStatus());
            groupDTO.setGroupOrder(NumberUtils.INTEGER_ZERO);

            // 遍历父组织与当前组织之前相隔的层级数, 设置组织的祖先节点数组, 然后设置需要新增的隐藏节点
            ServiceResult<List<UserGroupDTO>> hiddenServiceResult = setHiddenGroupsByResume(levelsResult.getData(), groupDTO, parentGroupDTO);
            if (!hiddenServiceResult.isSuccess()) {
                return ServiceResult.fail(hiddenServiceResult.getMsg());
            }

            // 校验同一个父组织下是否存在相同名称的组织, 如果存在的话则无法恢复该组织
            ServiceResult<GroupInfoDTO> checkRepectNameRt = this.checkRepectNameByParentGroup(groupDTO);
            if (!checkRepectNameRt.isSuccess()) {
                return ServiceResult.fail(checkRepectNameRt.getData(), checkRepectNameRt.getMsg(), checkRepectNameRt.getErrorCode());
            }

            // 添加隐藏节点
            List<UserGroupDTO> addHiddenGroups = hiddenServiceResult.getData();
            if (CollectionUtils.isNotEmpty(addHiddenGroups)) {
                this.insertBatch(addHiddenGroups);
            }

            // 更新失效组织的状态/层级id/祖先节点数组/版本号等信息
            this.updateByIdAndVersion(userGroupDTO.getVersionId(), groupDTO);

            // 判断父组织是否为有子节点，没有的话设置为有子节点
            if (!HaveChildrenFlagEnum.HAVE.getStatus().equals(parentGroupDTO.getHaveChildrenFlag())) {
                UserGroupDTO updateParentGroupParam = new UserGroupDTO();
                updateParentGroupParam.setOrgId(parentGroupDTO.getOrgId());
                updateParentGroupParam.setGroupId(parentGroupDTO.getGroupId());
                updateParentGroupParam.setOperatorId(groupDTO.getOperatorId());
                updateParentGroupParam.setUpdateTime(groupDTO.getUpdateTime());
                updateParentGroupParam.setHaveChildrenFlag(HaveChildrenFlagEnum.HAVE.getStatus());
                this.updateByIdAndVersion(parentGroupDTO.getVersionId(), updateParentGroupParam);
            }

            // 更新组织树的版本号
            groupSequenceUtil.incrementVersion(userGroupDTO.getOrgId());

            // 发送mq: 组织恢复(user.group_validate) 组织发生变化(user.groups_changed)
            // 组织恢复(user.group_validate)
            //userGroupMessageSender.publishGroupValidateList(userGroupDTO.getOrgId(), Collections.singletonList(userGroupDTO.getGroupId()));
            userMessageSendService.publishGroupValidateList(userGroupDTO.getOrgId(), Collections.singletonList(userGroupDTO.getGroupId()));
            //组织发生变化(user.groups_changed)
            //userGroupMessageSender.publishGroupsChange(userGroupDTO.getOrgId(), organizationDTO.getRootGroupId());
            userMessageSendService.publishGroupsChange(userGroupDTO.getOrgId(), organizationDTO.getRootGroupId());
        } finally {
            lock.unlock();
        }
        return ServiceResult.success();
    }

    /**
     * 恢复失效组织时, 判断是否存在组织编码重复, 如果存在则无法恢复改组织
     *
     * @param userGroupDTO 待恢复的组织
     * @return ServiceResult<Void>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/28 11:32
     */
    private ServiceResult<GroupInfoDTO> checkRepetCodeByResume(UserGroupDTO userGroupDTO) {
        // 校验参数
        if (StringUtils.isBlank(userGroupDTO.getGroupCode())) {
            return ServiceResult.success();
        }
        // 查询是否存在重复组织编码的有效状态的组织
        ServiceResult<List<UserGroupDTO>> groupsByCodeRt = this.listGroupsByCodes(userGroupDTO.getOrgId(), Collections.singletonList(userGroupDTO.getGroupCode()), Collections.singletonList(UserGroupStatusEnum.ACTIVATED.getStatus()));
        if (CollectionUtils.isEmpty(groupsByCodeRt.getData())) {
            return ServiceResult.success();
        }
        // 设置返回值
        return ServiceResult.fail(buildResumeFailGroup(groupsByCodeRt.getData().get(0)), "组织编码重复, 无法恢复", String.valueOf(ResourceErrorCodeEnum.FORBIDDEN.getCode()));
    }

    /**
     * 校验同一个父组织下是否存在相同名称的组织, 如果存在的话则无法恢复该组织
     *
     * @param groupDTO
     * @return ServiceResult<GroupInfoDTO>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/28 16:54
     */
    private ServiceResult<GroupInfoDTO> checkRepectNameByParentGroup(UserGroupDTO groupDTO) {
        // 校验参数
        if (StringUtils.isBlank(groupDTO.getGroupName()) || StringUtils.isBlank(groupDTO.getGroupParentId())) {
            return ServiceResult.success();
        }
        // 查询同一个父级组织下是否存在名称相同的组织
        UserGroupDTO userGroupDTO = new UserGroupDTO();
        userGroupDTO.setOrgId(groupDTO.getOrgId());
        userGroupDTO.setGroupParentId(groupDTO.getGroupParentId());
        userGroupDTO.setGroupName(groupDTO.getGroupName());
        userGroupDTO.setGroupStatus(UserGroupStatusEnum.ACTIVATED.getStatus());
        List<UserGroupDTO> groups = this.listByCondition(userGroupDTO).getData();
        if (CollectionUtils.isEmpty(groups)) {
            return ServiceResult.success();
        }
        // 设置返回值
        return ServiceResult.fail(buildResumeFailGroup(groups.get(0)), "组织名称重复, 无法恢复", String.valueOf(ResourceErrorCodeEnum.UPDATE_FORBID.getCode()));
    }

    /**
     * 设置恢复组织失败返回值
     *
     * @param repectGroup
     * @return GroupInfoDTO
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/28 17:34
     */
    private GroupInfoDTO buildResumeFailGroup(UserGroupDTO repectGroup) {
        GroupInfoDTO resumeFailDTO = userGroupConvert.dto2InfoDto(repectGroup);
        // 查询重复组织编码/重复组织名称的 组织的父级组织, 用于前端展示
        List<String> groupParentIds = JSON.parseArray(resumeFailDTO.getGroupParentIds(), String.class);
        if (CollectionUtils.isNotEmpty(groupParentIds)) {
            List<UserGroupDTO> parentGroups = this.listByGroupIds(groupParentIds).getData();
            if (CollectionUtils.isNotEmpty(parentGroups)) {
                // 根据层级给父组织进行排序
                Map<String, UserGroupDTO> idAndGroupMap = parentGroups.stream().collect(Collectors.toMap(UserGroupDTO::getGroupId, item -> item));
                List<UserGroupDTO> sortedParentGroups = new ArrayList<>();
                for (String groupParentId : groupParentIds) {
                    sortedParentGroups.add(idAndGroupMap.get(groupParentId));
                }
                // 设置父组织集合
                resumeFailDTO.setParentGroups(sortedParentGroups);
            }
        }

        return resumeFailDTO;
    }

    @Override
    public ServiceResult<Integer> updateByIdAndVersion(Integer versionId, UserGroupDTO groupDTO) {
        // 校验参数
        /*if (versionId == null) {
            return ServiceResult.fail("version_id 不能为空");
        }*/
        if (groupDTO == null) {
            return ServiceResult.fail("参数不能为空");
        }
        if (!ObjectId.isValid(groupDTO.getGroupId())) {
            return ServiceResult.fail("group_id 为空或者格式不正确");
        }

        // 更新, 并设置返回值
        return ServiceResult.success(userGroupDao.updateByIdAndVersion(versionId, userGroupConvert.dtoToDo(groupDTO)));
    }

    @Override
    public ServiceResult<Integer> updateByIdAndVersionWithNull(Integer versionId, UserGroupDTO groupDTO) {
        // 校验参数
        if (versionId == null) {
            return ServiceResult.fail("version_id 不能为空");
        }
        if (groupDTO == null) {
            return ServiceResult.fail("参数不能为空");
        }
        if (!ObjectId.isValid(groupDTO.getGroupId())) {
            return ServiceResult.fail("group_id 为空或者格式不正确");
        }

        // 更新, 并设置返回值
        return ServiceResult.success(userGroupDao.updateByIdAndVersionWithNull(versionId, userGroupConvert.dtoToDo(groupDTO)));
    }

    /**
     * 恢复失效组织: 通过group_id查询组织, 校验组织信息
     *
     * @param userGroupDTO
     * @return
     */
    private ServiceResult<UserGroupDTO> checkAndGetGroupByResume(UserGroupDTO userGroupDTO) {
        // 查询组织
        ServiceResult<UserGroupDTO> groupResult = this.getByIdAndOrgId(userGroupDTO.getGroupId(), userGroupDTO.getOrgId());
        if (!groupResult.isSuccess()) {
            return groupResult;
        }

        // 校验组织信息
        UserGroupDTO groupDTO = groupResult.getData();
        if (groupDTO == null) {
            return ServiceResult.fail("组织不存在");
        }
        if (!UserGroupStatusEnum.INACTIVATED.getStatus().equals(groupDTO.getGroupStatus())) {
            return ServiceResult.fail("组织状态必须为失效");
        }
        /*if (!userGroupDTO.getVersionId().equals(groupDTO.getVersionId())) {
            return ServiceResult.fail("组织已经变更, 请刷新重试");
        }*/

        return groupResult;
    }

    /**
     * 恢复失效组织: 通过group_parent_id查询组织, 并校验组织信息
     *
     * @param userGroupDTO
     * @return
     */
    private ServiceResult<UserGroupDTO> checkAndGetParentGroupByResume(UserGroupDTO userGroupDTO) {
        // 查询父组织
        ServiceResult<UserGroupDTO> parentGroupResult = this.getByIdAndOrgId(userGroupDTO.getGroupParentId(), userGroupDTO.getOrgId());
        if (!parentGroupResult.isSuccess()) {
            return ServiceResult.fail(parentGroupResult.getMsg());
        }

        // 校验父组织信息
        UserGroupDTO parentGroupDTO = parentGroupResult.getData();
        if (parentGroupDTO == null) {
            return ServiceResult.fail("父组织不存在");
        }
        if (!UserGroupStatusEnum.ACTIVATED.getStatus().equals(parentGroupDTO.getGroupStatus())) {
            return ServiceResult.fail("父组织状态必须为有效");
        }
        if (StringUtils.isBlank(parentGroupDTO.getGroupLevelId())) {
            return ServiceResult.fail("父组织的层级id为空");
        }
        if (parentGroupDTO.getGroupLevelId().equals(userGroupDTO.getGroupLevelId())) {
            return ServiceResult.fail("组织的所属层级不能与父组织的所属层级相同");
        }

        return parentGroupResult;
    }

    /**
     * 恢复失效组织:
     *
     * @param orgId
     * @return
     */
    private ServiceResult<Map<String, Integer>> checkAndGetLevelsByResume(String orgId) {
        // 查询公司层级
        ServiceResult<List<UserGroupLevelDTO>> levelsResult = userGroupLevelService.listByOrgId(orgId);
        if (!levelsResult.isSuccess()) {
            return ServiceResult.fail(levelsResult.getMsg());
        }

        // 校验公司层级
        List<UserGroupLevelDTO> groupLevelDTOS = levelsResult.getData();
        if (CollectionUtils.isEmpty(groupLevelDTOS)) {
            return ServiceResult.fail("公司层级信息不存在");
        }
        if (groupLevelDTOS.size() < BusinessConstant.USER_LEVEL_MIN_COUNT) {
            return ServiceResult.fail(String.format("公司层级数不能小于%d层", BusinessConstant.USER_LEVEL_MIN_COUNT));
        }
        if (groupLevelDTOS.size() > BusinessConstant.USER_LEVEL_MAX_COUNT) {
            return ServiceResult.fail(String.format("公司层级数不能大于%d层", BusinessConstant.USER_LEVEL_MAX_COUNT));
        }

        // 给公司层级排序, 设置返回值
        List<UserGroupLevelDTO> levelDTOS = groupLevelDTOS.stream().sorted(Comparator.comparingInt(UserGroupLevelDTO::getLevelNum)).collect(Collectors.toList());

        Map<String, Integer> levelMap = new LinkedHashMap<>();
        for (int i = 0; i < levelDTOS.size(); i++) {
            levelMap.put(levelDTOS.get(i).getGroupLevelId(), levelDTOS.get(i).getLevelNum());
        }

        return ServiceResult.success(levelMap);
    }

    /**
     * 恢复失效组织:
     *
     * @param levelMap       公司层级map
     * @param groupDTO       子组织
     * @param parentGroupDTO 父组织
     * @return
     */
    private ServiceResult<List<UserGroupDTO>> setHiddenGroupsByResume(Map<String, Integer> levelMap, UserGroupDTO groupDTO, UserGroupDTO parentGroupDTO) {
        // 校验参数
        Integer levelNum = levelMap.get(groupDTO.getGroupLevelId());
        Integer parentLevelNum = levelMap.get(parentGroupDTO.getGroupLevelId());
        if (levelNum == null) {
            return ServiceResult.fail("组织所属层级不存在");
        }
        if (parentLevelNum == null) {
            return ServiceResult.fail("父组织所属层级不存在");
        }
        if (levelNum.compareTo(parentLevelNum) <= 0) {
            return ServiceResult.fail("组织所属层级必须低于父组织所属层级");
        }

        // 定义组织的祖先节点id数组
        List<String> groupParentIds = Objects.nonNull(parentGroupDTO.getGroupParentIds()) ? JSON.parseArray(parentGroupDTO.getGroupParentIds(), String.class) : new ArrayList<>();
        groupParentIds.add(parentGroupDTO.getGroupId());

        // 设置隐藏节点的上一个节点
        UserGroupDTO hiddenGroupPrev = parentGroupDTO;
        // 设置返回值
        List<UserGroupDTO> hiddenGroups = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : levelMap.entrySet()) {
            String levelId = entry.getKey();
            // 如果当前层级在组织层级以及父组织层级之间,则添加隐藏节点
            if (levelMap.get(levelId).compareTo(parentLevelNum) > 0 && levelMap.get(levelId).compareTo(levelNum) < 0) {
                UserGroupDTO hiddenGroup = null;

                // 查询是否有对应的隐藏节点
                UserGroupDTO hiddenGroupQuery = new UserGroupDTO();
                hiddenGroupQuery.setOrgId(groupDTO.getOrgId());
                hiddenGroupQuery.setGroupLevelId(levelId);
                hiddenGroupQuery.setGroupParentId(hiddenGroupPrev.getGroupId());
                hiddenGroupQuery.setGroupStatus(UserGroupStatusEnum.HIDDEN.getStatus());
                List<UserGroupDTO> existHiddenGroups = this.listByCondition(hiddenGroupQuery).getData();

                // 判断是否已有隐藏节点
                if (CollectionUtils.isNotEmpty(existHiddenGroups)) {
                    // 已有对应的隐藏节点 直接设置
                    hiddenGroup = existHiddenGroups.get(0);
                } else {
                    // 没有对应的隐藏节点 新增
                    // 设置参数
                    hiddenGroup = new UserGroupDTO();
                    hiddenGroup.setGroupId(ObjectId.next());
                    hiddenGroup.setGroupLevelId(levelId);
                    hiddenGroup.setOrgId(hiddenGroupPrev.getOrgId());
                    hiddenGroup.setGroupStatus(UserGroupStatusEnum.HIDDEN.getStatus());
                    // 设置自动生成的组织编码参数
                    hiddenGroup.setGroupCode(this.generateGroupCode().getData());
                    hiddenGroup.setHaveChildrenFlag(HaveChildrenFlagEnum.HAVE.getStatus());
                    hiddenGroup.setSeq(sequenceService.incrementVersion(userCacheUtil.buildKey(UserCacheKeyConstant.USER_GROUP_SEQ, hiddenGroupPrev.getOrgId())));
                    hiddenGroup.setGroupName(hiddenGroupPrev.getGroupName());
                    hiddenGroup.setGroupParentId(hiddenGroupPrev.getGroupId());
                    hiddenGroup.setGroupParentIds(JSON.toJSONString(groupParentIds));
                    hiddenGroup.setGroupType(UserGroupTypeEnum.DEFAULT.getCode());
                    hiddenGroup.setVersionId(UserGroupConstant.INITIAL_VERSION);
                    hiddenGroup.setGroupOrder(NumberUtils.INTEGER_ZERO);
                    hiddenGroup.setGroupType(UserGroupTypeEnum.DEFAULT.getCode());
                    hiddenGroup.setCreateTime(groupDTO.getUpdateTime());
                    hiddenGroup.setUpdateTime(groupDTO.getUpdateTime());
                    hiddenGroup.setOperatorId(groupDTO.getOperatorId());
                    hiddenGroup.setCreatorId(groupDTO.getOperatorId());
                    hiddenGroups.add(hiddenGroup);
                }

                groupParentIds.add(hiddenGroup.getGroupId());
                hiddenGroupPrev = hiddenGroup;
            }
        }

        // 设置组织的父级节点和祖先节点id数组
        groupDTO.setGroupParentIds(JSON.toJSONString(groupParentIds));
        groupDTO.setGroupParentId(groupParentIds.get(groupParentIds.size() - 1));

        return ServiceResult.success(hiddenGroups);
    }

    @Override
    public ServiceResult<UserGroupDTO> getByIdAndOrgId(String groupId, String orgId) {
        // 校验参数
        if (!ObjectId.isValid(groupId) && !ObjectId.isValid(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, ReqErrorCodeEnum.PARAM_FORMAT.getMsg());
        }
        // 查询
        UserGroupDO userGroupDO = new UserGroupDO();
        userGroupDO.setGroupId(groupId);
        userGroupDO.setOrgId(orgId);
        List<UserGroupDO> userGroupDOS = userGroupDao.listByCondition(userGroupDO);
        // 设置返回值
        if (CollectionUtils.isNotEmpty(userGroupDOS)) {
            return ServiceResult.success(userGroupConvert.doToDto(userGroupDOS.get(0)));
        }
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<PageResponseDTO<UserGroupDTO>> layeredPage(String parentGroupId, String orgId, String userId, boolean isAdmin, Integer page, Integer size) {
        PageResponseDTO<UserGroupDTO> pageResult = new PageResponseDTO<>();
        // 只返回用户所属组织的一串层级(往上到顶和往下到底)，其它层级不返回；超管和系统管理员展示所有组织
        List<UserGroupDO> userGroupDOS = userGroupDao.listGroupByUserIdAndStatus(userId, UserGroupStatusEnum.ACTIVATED.getStatus());
        if (userGroupDOS.isEmpty() && !isAdmin) {
            // 如果普通操作员未挂到任何组织上，则不返回任何组织
            return ServiceResult.fail(ResourceErrorCodeEnum.OUT_OF_GROUP, "current user is out of group");
        }
        Set<String> parentIds = new HashSet<>();
        Set<String> currentIds = new HashSet<>();
        // 超管和系统管理员展示所有组织
        if (!isAdmin) {
            // 普通操作员只展示关联组织，及其上下级
            for (UserGroupDO userGroupDO : userGroupDOS) {
                currentIds.add(userGroupDO.getGroupId());
                parentIds.add(userGroupDO.getGroupId());
                if (userGroupDO.getGroupParentIds() != null) {
                    List<String> parentGroupIds = JSON.parseArray(userGroupDO.getGroupParentIds(), String.class);
                    parentIds.addAll(parentGroupIds);
                }
            }
        }

        // 查询指定父组织下一层的状态为【有效，隐藏的数量】
        List<Integer> statuses = Lists.newArrayList(UserGroupStatusEnum.ACTIVATED.getStatus(), UserGroupStatusEnum.HIDDEN.getStatus());
        long count = userGroupDao.countChild(parentGroupId, orgId, statuses, parentIds, currentIds);
        if (count <= 0) {
            return ServiceResult.success(pageResult);
        }
        // 查询列表
        List<UserGroupDO> userGroupDos = userGroupDao.listChild(parentGroupId, orgId, statuses, parentIds, currentIds, size, page);
        // DOS转DTOS
        List<UserGroupDTO> userGroupDtos = userGroupConvert.dosToDtos(userGroupDos);
        // 处理附加信息
        handleAdditionalInfo(orgId, userGroupDtos);
        pageResult = new PageResponseDTO<>(userGroupDtos, count, page);
        return ServiceResult.success(pageResult);
    }

    @Override
    public ServiceResult<GroupTreeDTO> getGroupTree(String orgId, String userId, boolean admin, boolean all) {
        long startTime = System.currentTimeMillis();
        List<UserGroup> groupsOfOrg = userGroupMapper.listByOrgIdAndStatuses(orgId, UserGroupStatusEnum.ACTIVATED.getStatus(), UserGroupStatusEnum.HIDDEN.getStatus());
        log.info("{}耗时：{}", "查询groupsOfOrg", System.currentTimeMillis() - startTime);
        startTime = System.currentTimeMillis();
        // 如果不展示所有，且不是超管和系统管理员，则对groupsOfOrg进行过滤
        if (!all && !admin) {
            List<UserGroup> groupsOfUser = userGroupMapper.listByUserIdAndStatus(userId, UserGroupStatusEnum.ACTIVATED.getStatus());
            log.info("{}耗时：{}", "查询groupsOfUser", System.currentTimeMillis() - startTime);
            startTime = System.currentTimeMillis();
            if (groupsOfUser == null || groupsOfUser.isEmpty()) {
                // 如果普通操作员未挂到任何组织上，则不返回任何组织
                return ServiceResult.fail(ResourceErrorCodeEnum.OUT_OF_GROUP, "current user is out of group");
            }
            Set<String> parentIds = new HashSet<>();
            Set<String> currentIds = new HashSet<>();
            // 普通操作员只展示关联组织，及其上下级
            for (UserGroup userGroup : groupsOfUser) {
                currentIds.add(userGroup.getGroupId());
                parentIds.add(userGroup.getGroupId());
                if (userGroup.getGroupParentIds() != null) {
                    List<String> parentGroupIds = JSON.parseArray(userGroup.getGroupParentIds(), String.class);
                    parentIds.addAll(parentGroupIds);
                }
            }

            // 过滤groupsOfOrg，过滤出用户有查看权限的节点
            groupsOfOrg = groupsOfOrg.stream().filter(group -> {
                // 用户绑定的节点，及这些节点的父节点
                if (parentIds.contains(group.getGroupId())) {
                    return true;
                }
                // 用户绑定的节点的子节点
                return currentIds.stream().anyMatch(groupId -> {
                    List<String> parentGroupIds = JSON.parseArray(group.getGroupParentIds(), String.class);
                    return parentGroupIds.contains(groupId);
                });
            }).collect(Collectors.toList());
            log.info("{}耗时：{}", "过滤groupsOfOrg，过滤出用户有查看权限的节点", System.currentTimeMillis() - startTime);
        }

        // 组装成组织tree
        GroupTreeDTO tree = list2Tree(groupsOfOrg);
        return ServiceResult.success(tree);
    }

    /**
     * 找到根节点，并将list拼装成组织树
     */
    private GroupTreeDTO list2Tree(List<UserGroup> list) {
        // 找到根节点
        List<UserGroup> roots = list.stream().filter(userGroup1 -> userGroup1.getGroupParentId() == null).collect(Collectors.toList());
        if (roots.size() > 1) {
            throw new RuntimeException("不能有多个根节点");
        }
        if (roots.isEmpty()) {
            return null;
        }
        UserGroup root = roots.get(0);

        // 拼装成树形结构
        return genTreeNode(list, root);
    }

    /**
     * 递归拼装组织层级树，每次拼装一个节点
     *
     * @param list  待拼装的组织列表
     * @param group 从该组织节点开始拼装
     * @return 递归生成的树
     */
    private GroupTreeDTO genTreeNode(List<UserGroup> list, UserGroup group) {
        GroupTreeDTO dto = new GroupTreeDTO();
        BeanUtils.copyProperties(group, dto);

        List<GroupTreeDTO> subList = new LinkedList<>();
        for (UserGroup userGroup : list) {
            // 递归拼装数据
            if (userGroup.getGroupParentId() != null && userGroup.getGroupParentId().equals(group.getGroupId())) {
                subList.add(genTreeNode(list, userGroup));
            }
        }
        dto.setSubGroups(subList);
        return dto;
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> getUserGroupUpper(String groupId, String userId, boolean isAdmin) {
        List<UserGroupDTO> result = new LinkedList<>();
        UserGroupDO userGroupDO = userGroupDao.getById(groupId);
        if (Objects.isNull(userGroupDO)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到指定的组织id对应的组织信息");
        }

        // 普通用户如果搜索的节点没有权限，直接返回空(超管未挂到组织上，但可以看到所有节点)
        if (!isAdmin) {
            Set<String> parentGroupIdsOfUser = getRelationAndParentGroupIdsOfUser(userId);
            if (parentGroupIdsOfUser.isEmpty()) {
                return ServiceResult.success(result);
            }
            List<String> currentAndChildrenGroupIdsOfUser = getChildrenGroupIdsByUserId(userGroupDO.getOrgId(), userId).getData();
            if (!parentGroupIdsOfUser.contains(groupId) && !currentAndChildrenGroupIdsOfUser.contains(groupId)) {
                return ServiceResult.success(result);
            }
        }

        Set<String> groupIds = new HashSet<>();
        groupIds.add(groupId);
        groupIds.addAll(JSON.parseArray(userGroupDO.getGroupParentIds(), String.class));
        List<UserGroupDO> userGroupDOs = userGroupDao.listByGroupIds(new ArrayList<>(groupIds));
        result.addAll(userGroupConvert.dosToDtos(userGroupDOs));

        // 处理附加信息
        handleAdditionalInfo(userGroupDO.getOrgId(), result);
        return ServiceResult.success(result);
    }

    @Override
    public ServiceResult<String> insertSelect(UserGroupDTO userGroup) {
        String groupId = userGroupDao.insertSelective(userGroupConvert.dtoToDo(userGroup));
        userGroup.setGroupId(groupId);
        return ServiceResult.success(groupId);
    }

    /**
     * 处理组织相关字段信息
     *
     * @param orgId  租户id
     * @param result 组织相关字段信息
     * @return void
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/02/08 15:30
     */
    private void handleAdditionalInfo(String orgId, List<UserGroupDTO> result) {
        if (CollectionUtils.isEmpty(result)) {
            return;
        }
        // 查询对应的层级名称
        ServiceResult<List<UserGroupLevelDTO>> listServiceResult = userGroupLevelService.listByOrgId(orgId);
        Map<String, UserGroupLevelDTO> groupLevelMap = new HashMap<>();
        String leafLevelId = "";
        if (listServiceResult.isSuccess() && CollectionUtils.isNotEmpty(listServiceResult.getData())) {
            groupLevelMap = listServiceResult.getData().stream().collect(Collectors.toMap(UserGroupLevelDTO::getGroupLevelId, u -> u));
            leafLevelId = listServiceResult.getData().stream().max(Comparator.comparing(UserGroupLevelDTO::getLevelNum)).map(UserGroupLevelDTO::getGroupLevelId).orElse("");
        }
        // 查询对应的用户数量
        List<String> groupIds = result.stream().map(UserGroupDTO::getGroupId).collect(Collectors.toList());
        ServiceResult<Map<String, Integer>> userCountByGroups = userUserGroupService.countUserNumByGroupIds(groupIds);
        Map<String, Integer> userCountMap = new HashMap<>();
        if (userCountByGroups.isSuccess() && null != userCountByGroups.getData()) {
            userCountMap = userCountByGroups.getData();
        }

        // 根据组织管理员id获取组织管理员名称信息
        List<String> adminIds = result.stream().map(UserGroupDTO::getAdminId).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
        Map<String, String> adminNameMap = new HashMap<>();

        ServiceResult<List<UserDTO>> userListResult = userService.selectByIds(adminIds);
        List<UserDTO> userDTOS = userListResult.getData();
        if (CollectionUtils.isNotEmpty(userDTOS)) {
            adminNameMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getUserId, UserDTO::getUserName, (c1, c2) -> c2));
        }
        for (UserGroupDTO userGroupDTO : result) {
            UserGroupLevelDTO userGroupLevelDTO = groupLevelMap.get(userGroupDTO.getGroupLevelId());
            if (Objects.nonNull(userGroupLevelDTO)) {
                // 设置层级名称
                userGroupDTO.setGroupLevelName(userGroupLevelDTO.getGroupLevelName());
                // 设置层级数
                userGroupDTO.setGroupLevelNum(userGroupLevelDTO.getLevelNum());
            }
            // 设置用户数量
            userGroupDTO.setUserNum(userCountMap.get(userGroupDTO.getGroupId()));
            // 设置管理员姓名
            if (StringUtils.isNotEmpty(userGroupDTO.getAdminId())) {
                userGroupDTO.setAdminName(adminNameMap.get(userGroupDTO.getAdminId()));
            }
            // 处理是否是叶子节点
            userGroupDTO.setLeafFlag(leafLevelId.equals(userGroupDTO.getGroupLevelId()) ? 1 : 0);
        }
    }

    /**
     * 编辑组织/重命名
     *
     * @param groupDTO 编辑组织参数
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/04/02 15:15
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ServiceResult<Integer> updateUserGroup(UpdateUserGroupDTO groupDTO) {
        // 校验数据的有效性
        if (Objects.isNull(groupDTO) || StringUtils.isEmpty(groupDTO.getGroupId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "参数不能为空");
        }
        UserGroupDO userGroupDo = userGroupDao.getById(groupDTO.getGroupId());
        if (Objects.isNull(userGroupDo)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到指定的组织信息");
        }
        if (!groupDTO.getVersionId().equals(userGroupDo.getVersionId())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "版本不一致，当前组织已发生变更");
        }
        if (userGroupDo.getGroupName().equals(groupDTO.getGroupName())) {
            return ServiceResult.success(groupDTO.getVersionId());
        }

        ServiceResult<UserGroupDTO> groupService = userGroupService.getById(groupDTO.getGroupId());
        UserGroupDTO userGroupDTO = groupService.getData();
        List<UserGroupDO> subGroupList = userGroupDao.listSubGroupByGroupId(groupDTO.getOrgId(), userGroupDTO.getGroupParentId());
        List<String> groupNameList = subGroupList.stream().map(UserGroupDO::getGroupName).collect(Collectors.toList());
        if (groupNameList.contains(groupDTO.getGroupName())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织名称重复");
        }

        UserGroupDO userGroupDO = new UserGroupDO();
        BeanUtils.copyProperties(groupDTO, userGroupDO);
        userGroupDO.setOperatorId(groupDTO.getOperatorId());
        userGroupDO.setVersionId(userGroupDO.getVersionId() + 1);
        userGroupDao.updateByIdAndVersion(groupDTO.getVersionId(), userGroupDO);
        // 递归更新隐藏节点的子组织且状态是隐藏的组织名称
        updateHiddenSubGroupName(groupDTO.getOrgId(), groupDTO.getGroupId(), groupDTO.getGroupName());
        // 更新整个树的版本号
        groupSequenceUtil.incrementVersion(userGroupDo.getOrgId());
        // 组织名称变更发送消息
        List<GroupNameInfo> title_modifys = new ArrayList<>();
        title_modifys.add(new GroupNameInfo(groupDTO.getGroupId(), userGroupDo.getGroupName(), groupDTO.getGroupName()));
        userMessageSendService.publishGroupTitleModifyList(userGroupDo.getOrgId(), title_modifys);
        // 组织改名发送MQ通知BI
        OrganizationDO organizationDO = organizationDao.selectByPrimaryKey(userGroupDo.getOrgId());
        userMessageSendService.publishGroupsChange(organizationDO.getOrgId(), organizationDO.getRootGroupId());

        return ServiceResult.success(userGroupDO.getVersionId());
    }

    /**
     * 移动组织
     *
     * @param groupDTO 移动数字参数
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Boolean>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/2/8 16:15
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ServiceResult<Integer> moveUserGroup(MoveUserGroupDTO groupDTO) {

        UserGroupDO moveGroup = userGroupDao.getById(groupDTO.getGroupId());
        UserGroupDO targetGroup = userGroupDao.getById(groupDTO.getTargetGroupId());
        if (Objects.isNull(moveGroup) || Objects.isNull(targetGroup)) {
            return ServiceResult.fail("组织不存在");
        }
        if (StringUtils.isBlank(moveGroup.getGroupParentId())) {
            return ServiceResult.fail("顶层组织不允许移动");
        }
        if (!moveGroup.getGroupParentId().equals(targetGroup.getGroupParentId())) {
            return ServiceResult.fail("移动的子组织不在同一层级");
        }
        Integer groupOrder = moveGroup.getGroupOrder();
        moveGroup.setGroupOrder(targetGroup.getGroupOrder());
        moveGroup.setVersionId(moveGroup.getVersionId() + 1);
        targetGroup.setGroupOrder(groupOrder);
        int result = userGroupDao.updateByIdAndVersion(groupDTO.getVersionId(), moveGroup);
        int target = userGroupDao.updateByIdAndVersion(targetGroup.getVersionId(), targetGroup);
        if (result == 0 || target == 0) {
            throw new ServiceException(ReqErrorCodeEnum.PARAM_LOST, "数据库操作失败，请重试");
        }
        return ServiceResult.success(moveGroup.getVersionId());
    }

    @Override
    public ServiceResult<String> generateGroupCode() {
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        return ServiceResult.success("Auto_" + timestamp.getTime() + String.format("%06d", RandomUtils.nextInt(0, 1000000)));
    }

    /**
     * 添加隐藏节点
     *
     * @param groupId 组织id
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Boolean>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/04/02 16:47
     */
    @Override
    public ServiceResult<Boolean> saveHiddenGroup(String groupId) {
        Date now = new Date();
        UserGroupDO groupDO = userGroupDao.getById(groupId);
        // 如果不存在子节点，则不需要添加隐藏节点，直接返回
        if (groupDO.getHaveChildrenFlag().equals(HaveChildrenFlagEnum.NOT_HAVE.getStatus())) {
            return ServiceResult.success(Boolean.TRUE);
        }
        // 查询父节点信息
        UserGroupDO parent = userGroupDao.getById(groupDO.getGroupParentId());

        // haveChildrenFlag不太准确 重新判断下
        if (Objects.isNull(parent)) {
            return ServiceResult.success(Boolean.TRUE);
        }

        // 隐藏节点
        UserGroupDO hiddenNode = new UserGroupDO();
        String hiddenNodeId = DataBaseUtil.generateId();
        hiddenNode.setGroupId(hiddenNodeId);
        hiddenNode.setGroupName(parent.getGroupName());
        ServiceResult<String> result = generateGroupCode();
        hiddenNode.setGroupCode(result.getData());
        hiddenNode.setGroupParentId(groupDO.getGroupParentId());
        hiddenNode.setGroupType(groupDO.getGroupType());
        hiddenNode.setGroupStatus(UserGroupStatusEnum.HIDDEN.getStatus());
        hiddenNode.setSeq(sequenceService.incrementVersion(userCacheUtil.buildKey(UserCacheKeyConstant.USER_GROUP_SEQ, groupDO.getOrgId())));
        hiddenNode.setOrgId(groupDO.getOrgId());
        hiddenNode.setGroupLevelId(groupDO.getGroupLevelId());
        hiddenNode.setCreatorId(SecurityContextHolder.getToken().getUserId());
        hiddenNode.setOperatorId(SecurityContextHolder.getToken().getUserId());
        hiddenNode.setCreateTime(now);
        hiddenNode.setUpdateTime(now);
        hiddenNode.setHaveChildrenFlag(groupDO.getHaveChildrenFlag());
        hiddenNode.setVersionId(UserGroupConstant.INITIAL_VERSION);
        hiddenNode.setGroupParentIds(groupDO.getGroupParentIds());
        hiddenNode.setGroupOrder(groupDO.getGroupOrder());
        userGroupDao.insertSelective(hiddenNode);
        // 查询子组织
        List<UserGroupDO> subGroupList = userGroupDao.getChildrenListByGroupId(groupId);
        for (UserGroupDO sub : subGroupList) {
            String newParentIds = sub.getGroupParentIds().replaceAll(groupId, hiddenNodeId);
            sub.setGroupParentIds(newParentIds);
            sub.setGroupParentId(hiddenNodeId);
            sub.setCreateTime(now);
            sub.setUpdateTime(now);
            sub.setGroupId(DataBaseUtil.generateId());
            userGroupDao.updateByIdAndVersion(sub.getVersionId(), sub);
        }
        return ServiceResult.success(Boolean.TRUE);
    }


    /**
     * 处理被删除层级下的组织
     *
     * @param orgId   公司id
     * @param levelId 被删除的层级id
     * @return com.bestcem.xm.util.ServiceResult<java.lang.Boolean>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/07/24 16:24
     */
    @Override
    public ServiceResult<Boolean> handleDeleteLevelGroup(String orgId, String levelId) {
        String userId = SecurityContextHolder.getToken().getUserId();
        Date now = new Date();
        // 查询被删除层级下的活动和隐藏组织
        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(GROUP_STATUS_ACTIVATED.getIndex());
        statusList.add(GroupStatusEnum.GROUP_STATUS_HIDDEN.getIndex());
        List<UserGroupDO> userGroupList = userGroupDao.getGroupByLevelIdAndStatusList(levelId, statusList);
        for (UserGroupDO groupDO : userGroupList) {
            // 查询父节点信息
            UserGroupDO parent = userGroupDao.getById(groupDO.getGroupParentId());

            // 递归更新隐藏节点的子组织且状态是隐藏的组织名称
            updateHiddenSubGroupName(orgId, groupDO.getGroupId(), parent.getGroupName());

            // 不查询叶子节点因为一定不存在
            if (NumberUtils.INTEGER_ONE.equals(groupDO.getHaveChildrenFlag())) {
                // 查询子组织
                List<UserGroupDO> subGroupList = userGroupDao.getAllSubGroup(orgId, groupDO.getGroupId());
                // 更新子组织的groupParentId和groupParentIds
                for (UserGroupDO sub : subGroupList) {
                    // 重置groupParentId
                    if (sub.getGroupParentId().equals(groupDO.getGroupId())) {
                        sub.setGroupParentId(parent.getGroupId());
                        // 和父组织下的子组织重名的情况
                        List<Integer> statuses = Arrays.asList(UserGroupStatusEnum.ACTIVATED.getStatus(), UserGroupStatusEnum.HIDDEN.getStatus());
                        List<UserGroupDO> userGroupDOList = userGroupDao.listChildrenByGroupIdAndStatus(parent.getGroupId(), statuses);
                        List<String> groupNameList = userGroupDOList.stream().map(UserGroupDO::getGroupName).collect(Collectors.toList());
                        if (groupNameList.contains(sub.getGroupName()) && sub.getGroupStatus().equals(UserGroupStatusEnum.ACTIVATED.getStatus())) {
                            sub.setGroupName(groupDO.getGroupName() + "-" + sub.getGroupName());
                        }
                    }
                    String oldParentIds = sub.getGroupParentIds();
                    JSONArray oldParentIdArray = JSON.parseArray(oldParentIds);
                    oldParentIdArray.remove(groupDO.getGroupId());
                    sub.setGroupParentIds(JSON.toJSONString(oldParentIdArray));
                    sub.setUpdateTime(now);
                }
                // 批量更新组织
                if (CollectionUtils.isNotEmpty(subGroupList)) {
                    userGroupDao.batchUpdateById(subGroupList);
                }
            }
        }
        List<String> groupIds = userGroupList.stream().map(UserGroupDO::getGroupId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(groupIds)) {
            userGroupDao.updateChildrenStatus(groupIds, userId, UserGroupStatusEnum.DELETED.getStatus());
        }
        // 组织批量失效发送消息 (删除也发送失效的消息，python统一处理)
        userMessageSendService.publishGroupInvalidateList(orgId, groupIds);
        return ServiceResult.success(Boolean.TRUE);
    }


    @Override
    public ServiceResult<Boolean> saveHiddenGroupForLevel(String orgId, String upperLevelId, String lowerLevelId, String newLevelId) {
        Date now = new Date();
        UserGroupDO check = new UserGroupDO();
        check.setOrgId(orgId);
        check.setGroupLevelId(upperLevelId);
        // 待插入层级的上级层级下的组织，因为要添加隐藏节点 故查询
        List<UserGroupDO> upperGroupDOList = userGroupDao.listByCondition(check);
        for (UserGroupDO groupDO : upperGroupDOList) {
            // 如果不存在子节点，则不需要添加隐藏节点，直接返回
            if (groupDO.getHaveChildrenFlag().equals(HaveChildrenFlagEnum.NOT_HAVE.getStatus())) {
                continue;
            }

            // 隐藏节点
            UserGroupDO hiddenNode = new UserGroupDO();
            hiddenNode.setGroupName(groupDO.getGroupName());
            ServiceResult<String> result = generateGroupCode();
            hiddenNode.setGroupCode(result.getData());
            hiddenNode.setGroupParentId(groupDO.getGroupId());
            hiddenNode.setGroupType(groupDO.getGroupType());
            hiddenNode.setGroupStatus(UserGroupStatusEnum.HIDDEN.getStatus());
            hiddenNode.setSeq(sequenceService.incrementVersion(userCacheUtil.buildKey(UserCacheKeyConstant.USER_GROUP_SEQ, groupDO.getOrgId())));
            hiddenNode.setOrgId(groupDO.getOrgId());
            hiddenNode.setGroupLevelId(newLevelId);
            hiddenNode.setCreatorId(SecurityContextHolder.getToken().getUserId());
            hiddenNode.setOperatorId(SecurityContextHolder.getToken().getUserId());
            hiddenNode.setCreateTime(now);
            hiddenNode.setUpdateTime(now);
            hiddenNode.setHaveChildrenFlag(groupDO.getHaveChildrenFlag());
            hiddenNode.setVersionId(UserGroupConstant.INITIAL_VERSION);

            String parentGroupParentIds = groupDO.getGroupParentIds();
            JSONArray parentParentIdArray = JSON.parseArray(parentGroupParentIds);
            parentParentIdArray.add(groupDO.getGroupId());
            hiddenNode.setGroupParentIds(JSON.toJSONString(parentParentIdArray));
            hiddenNode.setGroupOrder(groupDO.getGroupOrder());
            String hiddenNodeId = userGroupDao.insertSelective(hiddenNode);
            // 查询下级层级下的活动和隐藏组织 不查询叶子节点因为一定不存在
            if (NumberUtils.INTEGER_ONE.equals(groupDO.getHaveChildrenFlag())) {
//                List<UserGroupDO> subGroupList = userGroupDao.getAllSubGroup(orgId, groupDO.getGroupId());
//                for (UserGroupDO sub : subGroupList) {
//                    if (sub.getGroupId().equals(hiddenNodeId)) {
//                        continue;
//                    }
//                    // 重置groupParentId
//                    if (sub.getGroupParentId().equals(groupDO.getGroupId())) {
//                        sub.setGroupParentId(hiddenNodeId);
//                    }
//                    String oldParentIds = sub.getGroupParentIds();
//                    JSONArray oldParentIdArray = JSON.parseArray(oldParentIds);
//                    oldParentIdArray.add(hiddenNodeId);
//                    sub.setGroupParentIds(JSON.toJSONString(oldParentIdArray));
//                    sub.setCreateTime(now);
//                    sub.setUpdateTime(now);
//                }
//                // 批量更新组织
//                if (CollectionUtils.isNotEmpty(subGroupList)) {
//                    userGroupDao.batchUpdateById(subGroupList);
//                }
                // 待插入层级的上级层级下的组织，因为要添加了隐藏节点，所以需要更新子孙组织的group_parent_id和group_parent_ids
                updateParentIdAndParentIds(orgId, groupDO, hiddenNodeId, groupDO.getGroupId());
            }
            // 递归更新隐藏节点的子组织且状态是隐藏的组织名称
            updateHiddenSubGroupName(orgId, groupDO.getGroupId(), groupDO.getGroupName());
        }
        return ServiceResult.success(Boolean.TRUE);
    }

    /**
     * 待插入层级的上级层级下的组织，因为要添加了隐藏节点，所以需要更新子孙组织的group_parent_id和group_parent_ids
     * 递归更新子孙组织的group_parent_id和group_parent_ids
     *
     * @param orgId
     * @param parent   待插入层级的上级层级下的组织
     * @param hiddenId 隐藏节点的组织id
     * @param parentId 待插入层级的上级层级下的组织id 用于判断是否需要更新group_parent_id 因为添加隐藏节点后 group_parent_id 变成隐藏节点的id
     * @return void
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/08/26 09:38
     */
    private void updateParentIdAndParentIds(String orgId, UserGroupDO parent, String hiddenId, String parentId) {
        Date now = new Date();
        // 叶子节点不查询 减少查询
        if (NumberUtils.INTEGER_ONE.equals(parent.getHaveChildrenFlag())) {
            ArrayList<Integer> statusList = new ArrayList<>();
            statusList.add(GROUP_STATUS_ACTIVATED.getIndex());
            statusList.add(GroupStatusEnum.GROUP_STATUS_HIDDEN.getIndex());
            // 挂载在待插入层级的上级层级下的组织的子组织
            List<UserGroupDO> userGroupList = userGroupDao.listChildrenByGroupIdAndStatus(parent.getGroupId(), statusList);
            for (UserGroupDO userGroupDO : userGroupList) {
                if (userGroupDO.getGroupId().equals(hiddenId)) {
                    continue;
                }
                // 原来挂载在待插入层级的上级层级下的组织 由于添加了隐藏节点需要重置groupParentId
                if (userGroupDO.getGroupParentId().equals(parentId)) {
                    userGroupDO.setGroupParentId(hiddenId);
                }
                // 由于插入了隐藏节点, 所以需要更新group_parent_ids
                String oldParentIds = parent.getGroupParentIds();
                JSONArray oldParentIdArray = JSON.parseArray(oldParentIds);
                oldParentIdArray.add(parent.getGroupId());
                userGroupDO.setGroupParentIds(JSON.toJSONString(oldParentIdArray));
                userGroupDO.setUpdateTime(now);
            }
            // 批量更新组织
            if (CollectionUtils.isNotEmpty(userGroupList)) {
                userGroupDao.batchUpdateById(userGroupList);
                for (UserGroupDO userGroupDO : userGroupList) {
                    updateParentIdAndParentIds(orgId, userGroupDO, hiddenId, parentId);
                }
            }
        }

    }

    /**
     * 递归更新隐藏节点的子组织且状态是隐藏的组织名称
     *
     * @param orgId     公司id
     * @param groupId   父组织id
     * @param groupName 组织名称
     * @return void
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/07/24 16:19
     */
    private void updateHiddenSubGroupName(String orgId, String groupId, String groupName) {
        List<UserGroupDO> subGroupList = userGroupDao.listSubGroupByGroupId(orgId, groupId);
        if (CollectionUtils.isNotEmpty(subGroupList)) {
            for (UserGroupDO subGroup : subGroupList) {
                // 必须是隐藏节点才更新
                if (subGroup.getGroupStatus().equals(UserGroupStatusEnum.HIDDEN.getStatus())) {
                    userGroupDao.updateHiddenGroupName(orgId, subGroup.getGroupId(), groupName);
                    updateHiddenSubGroupName(orgId, subGroup.getGroupId(), groupName);
                }
            }
        }
    }

    /**
     * 根据父组织id获取子组织的最大order
     *
     * @param groupId 父组织id
     * @return java.lang.Integer
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/7/5 18:56
     */
    @Override
    public Integer getMaxChildrenOrderByGroupId(String groupId) {
        List<UserGroupDO> childrenList = userGroupDao.getChildrenListByGroupId(groupId);
        if (CollectionUtils.isEmpty(childrenList)) {
            return NumberUtils.INTEGER_ZERO;
        }
        UserGroupDO maxOrderGroup = childrenList.stream().filter(t -> Objects.nonNull(t.getGroupOrder())).max(Comparator.comparing(UserGroupDO::getGroupOrder)).orElse(null);
        if (Objects.isNull(maxOrderGroup) || Objects.isNull(maxOrderGroup.getGroupOrder())) {
            return NumberUtils.INTEGER_ZERO;
        }
        return maxOrderGroup.getGroupOrder() + 1;
    }

    /**
     * 新增隐藏节点
     *
     * @param parentGroup
     * @param userId
     * @param requestLevelNum
     * @return com.bestcem.xm.user.service.dto.group.UserGroupDTO
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/4/27 16:33
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserGroupDO createHiddenGroup(UserGroupDO parentGroup, String userId, Integer requestLevelNum, List<UserGroupLevelDO> levels) {

        // 得到当前层级与所选层级之间的所有子层级
        ServiceResult<UserGroupLevelDTO> parentLevel = userGroupLevelService.getById(parentGroup.getGroupLevelId());
        List<UserGroupLevelDO> groupLevelDOList = levels.stream().filter(l -> l.getLevelNum() > parentLevel.getData().getLevelNum() && l.getLevelNum() < requestLevelNum).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(groupLevelDOList)) {
            return null;
        }

        List<String> groupParentIds = JSON.parseArray(parentGroup.getGroupParentIds(), String.class);
        ArrayList<UserGroupDO> groups = new ArrayList<>();
        UserGroupDO parentGroupPre = parentGroup;
        int seq = sequenceService.incrementVersion(userCacheUtil.buildKey(UserCacheKeyConstant.USER_GROUP_SEQ, parentGroupPre.getOrgId()));

        for (UserGroupLevelDO userGroupLevelDO : groupLevelDOList) {
            UserGroupDO userGroup = new UserGroupDO();
            String generateId = DataBaseUtil.generateId();
            userGroup.setGroupId(generateId);
            userGroup.setGroupName(parentGroupPre.getGroupName());
            userGroup.setGroupCode(generateGroupCode().getData());
            userGroup.setGroupType(UserGroupConstant.INITIAL_TYPE);
            userGroup.setGroupStatus(UserGroupStatusEnum.HIDDEN.getStatus());
            userGroup.setGroupOrder(getMaxChildrenOrderByGroupId(parentGroupPre.getGroupId()));
            userGroup.setHaveChildrenFlag(HaveChildrenFlagEnum.HAVE.getStatus());
            userGroup.setVersionId(UserGroupConstant.INITIAL_VERSION);
            userGroup.setSeq(seq);
            userGroup.setGroupParentId(parentGroupPre.getGroupId());
            userGroup.setOrgId(parentGroupPre.getOrgId());
            userGroup.setGroupLevelId(userGroupLevelDO.getGroupLevelId());
            groupParentIds.add(parentGroupPre.getGroupId());
            userGroup.setGroupParentIds(JSON.toJSONString(groupParentIds));
            userGroup.setCreatorId(userId);
            userGroup.setOperatorId(userId);

            groups.add(userGroup);
            parentGroupPre = userGroup;
            seq++;
        }

        // 批量新增
        userGroupDao.hiddenGroupInsertBatch(groups);
        userCacheUtil.setEx(userCacheUtil.buildKey(UserCacheKeyConstant.USER_GROUP_SEQ, parentGroupPre.getOrgId()), String.valueOf(seq));
        return CollectionUtils.isNotEmpty(groups) ? groups.get(groups.size() - 1) : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<CreateGroupResponseVO> createSubGroup(UserGroupDTO dto, TokenDTO currentToken) {
        // 判断组织编码是否可用
        String orgId = currentToken.getOrgId();
        ServiceResult<Boolean> checkGroupCode = checkGroupCode(dto.getGroupCode(), orgId);
        if (Boolean.FALSE.equals(checkGroupCode.getData())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "组织编码重复");
        }

        // 检验groupParentId
        String groupParentId = dto.getGroupParentId();
        ServiceResult<UserGroupDTO> parentGroupService = userGroupService.getById(groupParentId);
        UserGroupDTO parentGroupDTO = parentGroupService.getData();
        if (Objects.isNull(parentGroupDTO)) {
            return ServiceResult.fail("父组织id不正确");
        }

        // 按levelNum升序排序
        List<UserGroupLevelDO> levelDos = userGroupLevelDao.getGroupLevelsByOrgId(orgId);
        Map<String, UserGroupLevelDO> idLevelMap = levelDos.stream().collect(Collectors.toMap(UserGroupLevelDO::getGroupLevelId, Function.identity()));
        Map<String, Integer> levelIdNumMap = levelDos.stream().collect(Collectors.toMap(UserGroupLevelDO::getGroupLevelId, UserGroupLevelDO::getLevelNum));

        // 判断层级Id是否符合逻辑
        UserGroupLevelDO parentLevel = idLevelMap.get(parentGroupDTO.getGroupLevelId());
        UserGroupLevelDO requestLevel = idLevelMap.get(dto.getGroupLevelId().toLowerCase());
        if (Objects.isNull(requestLevel)) {
            return ServiceResult.fail("所属层级id不正确");
        }
        if (requestLevel.getLevelNum() <= parentLevel.getLevelNum()) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "所属层级数必须大于父组织所在层级数，请重新选择");
        }

        String userId = currentToken.getUserId();
        UserGroupDO parentGroup = userGroupConvert.dtoToDo(parentGroupDTO);
        String groupLevelId = requestLevel.getGroupLevelId();
        String levelChildrenId = parentLevel.getLevelChildrenId();
        while (!groupLevelId.equals(levelChildrenId)) {
            // 判断父组织下有无隐藏节点
            UserGroupDO userGroupDO = new UserGroupDO();
            userGroupDO.setOrgId(orgId);
            userGroupDO.setGroupStatus(UserGroupStatusEnum.HIDDEN.getStatus());
            userGroupDO.setGroupParentId(groupParentId);
            userGroupDO.setGroupName(parentGroupDTO.getGroupName());
            ServiceResult<UserGroupDO> hiddenGroup = userGroupService.getUserGroupByCondition(userGroupDO);

            if (Objects.isNull(hiddenGroup.getData())) {
                // 补中间的隐藏节点
                UserGroupDO groupDO = createHiddenGroup(parentGroup, userId, requestLevel.getLevelNum(), levelDos);
                parentGroup = Objects.nonNull(groupDO) ? groupDO : parentGroup;
                break;
            }

            // 有隐藏节点则继续往下一个层级判断
            if (StringUtils.isNotBlank(levelChildrenId)) {
                parentGroup = hiddenGroup.getData();
                groupParentId = hiddenGroup.getData().getGroupId();
                ServiceResult<UserGroupLevelDTO> byId = userGroupLevelService.getById(levelChildrenId);
                if (!byId.isSuccess()) {
                    return ServiceResult.fail(byId.getMsg());
                }
                levelChildrenId = Objects.nonNull(byId.getData()) ? byId.getData().getLevelChildrenId() : null;
                continue;
            }
            break;
        }

        // 判断同父组织同层级的组织名称不能重复
        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(UserGroupStatusEnum.ACTIVATED.getStatus());
        statusList.add(UserGroupStatusEnum.HIDDEN.getStatus());
        long nameCount = userGroupDao.getByNameAndLevelId(dto.getGroupName(), parentGroup.getGroupId(), dto.getGroupLevelId(), orgId, statusList);
        if (nameCount != 0) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "同父组织同层级的组织名称不能重复!");
        }

        // 获取父组织的groupParentIds
        String groupParentIdString = parentGroup.getGroupParentIds();
        List<String> groupParentIds = JSON.parseArray(groupParentIdString, String.class);
        String groupId = parentGroup.getGroupId();
        groupParentIds.add(groupId);

        // 添加子组织
        UserGroupDTO userGroup = new UserGroupDTO();
        userGroup.setGroupId(DataBaseUtil.generateId());
        userGroup.setGroupName(dto.getGroupName());
        userGroup.setGroupCode(dto.getGroupCode());
        userGroup.setGroupType(UserGroupConstant.INITIAL_TYPE);
        userGroup.setGroupStatus(UserGroupStatusEnum.ACTIVATED.getStatus());
        userGroup.setGroupOrder(getMaxChildrenOrderByGroupId(groupId));
        userGroup.setHaveChildrenFlag(HaveChildrenFlagEnum.NOT_HAVE.getStatus());
        userGroup.setSeq(sequenceService.incrementVersion(userCacheUtil.buildKey(UserCacheKeyConstant.USER_GROUP_SEQ, orgId)));
        userGroup.setVersionId(UserGroupConstant.INITIAL_VERSION);
        userGroup.setGroupParentId(parentGroup.getGroupId());
        userGroup.setOrgId(orgId);
        userGroup.setGroupLevelId(dto.getGroupLevelId());
        userGroup.setGroupParentIds(JSON.toJSONString(groupParentIds));
        userGroup.setCreatorId(userId);
        userGroup.setOperatorId(userId);
        insertSelect(userGroup);

        // 更新父组织have_children_flag字段
        userGroupDao.updateHaveChildrenFlag(dto.getGroupParentId(), HaveChildrenFlagEnum.HAVE.getStatus());

        // 发送新增组织消息
        UserGroupDO userGroupDO = userGroupDao.getRootGroupByOrgId(orgId);
        String rootGroupId = StringUtils.isNotBlank(userGroupDO.getGroupId()) ? userGroupDO.getGroupId() : "";
        // 新增组织发送MQ通知BI
        OrganizationDO organizationDO = organizationDao.selectByPrimaryKey(userGroupDO.getOrgId());
        userMessageSendService.publishGroupsChange(organizationDO.getOrgId(), organizationDO.getRootGroupId());

        Integer levelNum = levelIdNumMap.get(dto.getGroupLevelId().toLowerCase());
        UserGroupLevelDO userGroupLevelDO = levelDos.get(levelDos.size() - 1);
        // 如果是叶子节点
        if (levelNum.equals(userGroupLevelDO.getLevelNum())) {
            // 发送新增门店mq消息
            StoreInfo storeInfo = new StoreInfo(userGroup.getGroupId(), userGroup.getGroupCode(), userGroup.getGroupName(), null);
            userMessageSendService.publishCreateStoreList(orgId, rootGroupId, Collections.singletonList(storeInfo));
            userGroup.setLeafFlag(BooleanStatusEnum.YES.getStatus());
        } else {
            userGroup.setLeafFlag(BooleanStatusEnum.NO.getStatus());
        }
        userGroup.setGroupLevelNum(levelNum);
        userGroup.setGroupLevelName(requestLevel.getGroupLevelName());

        return ServiceResult.success(userGroupConvert.dtoToVo(userGroup));
    }

    @Override
    public ServiceResult<Integer> setAdminId(UserGroupDTO dto) {
        // 参数校验
        if (!ObjectId.isValid(dto.getAdminId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "userId为空或者格式不正确");
        }
        if (!ObjectId.isValid(dto.getGroupId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "groupId为空或者格式不正确");
        }

        int row = userGroupDao.setAdminId(userGroupConvert.dtoToDo(dto));
        if (row == 0) {
            return ServiceResult.fail("数据库操作失败，请重试");
        }
        return ServiceResult.success();
    }


    /**
     * 根据用户id获取组织列表
     *
     * @param param 根据用户id获取组织列表参数
     * @return com.bestcem.xm.user.service.dto.group.PageDTO<com.bestcem.xm.user.service.dto.group.UserGroupDTO>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/04/02 16:48
     */
    @Override
    public PageResponseDTO<UserGroupDTO> getGroupListByUserId(UserGroupListByUserIdParam param) {
        ServiceResult<List<String>> result = userUserGroupService.getGroupIdsByUserId(param.getUserId());
        if (CollectionUtils.isNotEmpty(result.getData())) {
            Long total = userGroupDao.listByGroupIdsByUserIdCount(result.getData(), param.getIncludeChildFlag(), param.getFilterStatusFlag());
            List<UserGroupDO> userGroupList = userGroupDao.listByGroupIdsByUserId(result.getData(), param.getIncludeChildFlag(), param.getFilterStatusFlag(), param.getPageParam());
            List<UserGroupDTO> userGroupDTOList = userGroupConvert.dosToDtos(userGroupList);
            return new PageResponseDTO<>(userGroupDTOList, total, param.getPageParam().getPage());

        }
        return new PageResponseDTO<>(new ArrayList<>(), 0L, param.getPageParam().getPage());
    }

    @Override
    public List<UserGroupDTO> listByOrgIdOrPage(GetGroupsByOrgIdOrPage page) {
        List<UserGroupDO> userGroupList = userGroupDao.listByOrgIdOrPage(page.getOrgId(), page.getPageParam().getOffset(), page.getPageParam().getSize(), page.isPageFlag());
        return userGroupConvert.dosToDtos(userGroupList);
    }

    /**
     * 根据指定用户组id和层级id 分页查询指定层级上的子用户组列表
     *
     * @param groupId         组织id
     * @param groupLevelId    层级id
     * @param includeInactive 是否包含失效节点
     * @param currentPage     第几页
     * @param pageSize        每页大小
     * @return com.bestcem.xm.util.ServiceResult<com.bestcem.xm.user.group.service.dto.group.PageDTO < com.bestcem.xm.user.group.service.dto.group.UserGroupDTO>>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/02/24 11:56
     */
    @Override
    public ServiceResult<PageResponseDTO<UserGroupDTO>> pageChildrenByGroupIdAndLevelId(String groupId, String groupLevelId, boolean includeInactive, int currentPage, int pageSize) {
        // 参数校验
        if (!ObjectId.isValid(groupId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织id不能为空或格式不正确");
        }
        if (!ObjectId.isValid(groupLevelId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "层级id不能为空或格式不正确");
        }
        if (currentPage <= 0) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "当前页不能小于1");
        }
        if (pageSize <= 0) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "每页大小不能小于1");
        }

        // 构造查询参数
        List<Integer> statusList = new ArrayList<>();
        statusList.add(GROUP_STATUS_ACTIVATED.getIndex());
        statusList.add(GroupStatusEnum.GROUP_STATUS_HIDDEN.getIndex());
        if (includeInactive) {
            statusList.add(GroupStatusEnum.GROUP_STATUS_INACTIVATED.getIndex());
        }

        // 统计数量
        long count = userGroupDao.countChildrenNum(groupId, groupLevelId, statusList);
        PageResponseDTO<UserGroupDTO> page = new PageResponseDTO<>();
        if (count == 0) {
            page.setTotal(0L);
            return ServiceResult.success(page);
        }
        // 分页查询列表
        List<UserGroupDO> userGroupDOs = userGroupDao.listPageChildren(groupId, groupLevelId, statusList, pageSize, currentPage);
        page = new PageResponseDTO<>(userGroupConvert.dosToDtos(userGroupDOs), count, currentPage);
        return ServiceResult.success(page);
    }

    /**
     * 根据根据user_id获取祖先层级(包含用户所在层级)ids
     *
     * @param userId 用户Id
     * @return List<String>
     * @author yanjishuo <jishuo.yan@idiaoyan.cn>
     * @date 2022/02/24 17:30
     */
    @Override
    public ServiceResult<List<String>> getSelfAndParentIds(String userId) {
        // 参数校验
        if (!ObjectId.isValid(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "userId为空或者格式不正确");
        }
        // 获取用户所在组织
        List<UserGroupDO> userGroupDOS = userGroupDao.listGroupByUserId(userId);
        userGroupDOS = userGroupDOS.stream().filter(u -> u.getGroupStatus().equals(UserGroupStatusEnum.ACTIVATED.getStatus())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(userGroupDOS)) {
            return ServiceResult.success(new ArrayList<>());
        }
        Set<String> parentIds = new HashSet<>();
        for (UserGroupDO groupDO : userGroupDOS) {
            parentIds.add(groupDO.getGroupId());
            String groupParentIds = groupDO.getGroupParentIds();
            if (StringUtils.isNotBlank(groupParentIds)) {
                parentIds.addAll(JSON.parseArray(groupParentIds, String.class));
            }
        }
        return ServiceResult.success(Lists.newArrayList(parentIds));
    }

    /**
     * 根据根据user_id获取祖先层级(包含用户所在层级)ids
     *
     * @param userId 用户Id
     * @return List<String>
     * @author yanjishuo <jishuo.yan@idiaoyan.cn>
     * @date 2022/02/24 17:30
     */
    @Override
    public ServiceResult<List<String>> getSelfAndParentIdsOrder(String userId) {
        // 参数校验
        if (!ObjectId.isValid(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "userId为空或者格式不正确");
        }
        // 获取用户所在组织
        List<UserGroupDO> userGroupDOS = userGroupDao.listGroupByUserIdAndOrder(userId);
        userGroupDOS = userGroupDOS.stream().filter(u -> u.getGroupStatus().equals(UserGroupStatusEnum.ACTIVATED.getStatus())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(userGroupDOS)) {
            return ServiceResult.success(new ArrayList<>());
        }
        List<String> parentIds = new ArrayList<>();
        for (UserGroupDO groupDO : userGroupDOS) {
            parentIds.add(groupDO.getGroupId());
            String groupParentIds = groupDO.getGroupParentIds();
            if (StringUtils.isNotBlank(groupParentIds)) {
                for (String parentId : JSON.parseArray(groupParentIds, String.class)) {
                    if (!parentIds.contains(parentId)) {
                        parentIds.add(parentId);
                    }
                }
            }
        }
        return ServiceResult.success(parentIds);
    }

    /**
     * 递归获取孩子节点
     *
     * @param groupNode:       组织节点
     * @param includeInactive: 是否包含
     * @return
     * @author Linked <zhijian.lin@idiaoyan.com>
     * @date 2022/2/28 16:54
     */
    @Override
    public void setGroupTree(GroupNodeDTO groupNode, boolean includeInactive) {
        List<GroupNodeDTO> children = userGroupDao.getChildrenGroup(groupNode.getId(), includeInactive);
        if (CollectionUtils.isNotEmpty(children)) {
            for (GroupNodeDTO node : children) {
                List<GroupNodeDTO> groupList = userGroupDao.getChildrenGroup(node.getId(), includeInactive);
                if (CollectionUtils.isNotEmpty(groupList)) {
                    setGroupTree(node, includeInactive);
                }
            }
            groupNode.setChildren(children);
        }
    }

    /**
     * 组织失效关联的其他逻辑需要异步执行
     *
     * @param groupId        当前失效的用户组id
     * @param parentId       当前失效的用户组的父组织id
     * @param groupParentIds 当前失效的用户组的所有父组织id
     * @param userId         用户id
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/02/18 14:29
     */
    public void groupInvalidSyncTask(String groupId, String parentId, List<String> groupParentIds, String userId, String orgId) {
        executor.execute(() -> {
            /*
             * 1. 根据当前组织节点递归查询上一级的影藏节点，如果上一级的影藏节点需要被标记为已删除，则继续递归，否则停止递归
             * - 1.1 默认存储一个变量，用来最后更新所有parentId的指向跳过已删除节点的处理逻辑，默认该变量maxHidenId=当前节点id；
             * - 1.2 判断隐藏节点下是否有【有效状态】的组织信息，如果没有，表明当前节点需要被表示为【已删除状态】，同时将将表示为【已删除状态】节点的所有子节点【已失效】的parentIds去除已删除节点的id；
             * - 1.2 将处于最上面的被标为【已删除】的节点的id记录下来，如果没有则记录当前节点，标记为maxHidenId；
             * 2. 根据当前组织节点查询下面所有的隐藏节点列表
             * - 2.1 如果有影藏节点，由于所有的子节点同步标为失效，所以影藏节点下都没有有效节点，所以直接将隐藏节点则标记为已删除
             * - 2.2 同时将所有影藏节点下的所有子节点【已失效】的parentIds去除隐藏除节点的id；
             * 3. 更新parentId的指向，由于隐藏节点被标记为已删除，则下一层的指向需要重新指向到上一层未删除的节点；具体操作如下
             * - 3.1 根据第一步的maxHidenId来更新所有的子节点的parentId为parentIds的最后一个；
             */
            // 1. 批量查询当前节点的所有影藏的父节点
            RLock lock = redisService.getLock(GROUP_INVALID_LOCK + orgId);
            lock.lock();
            try {
                String lastNotHiddenGroup = null;
                if (CollectionUtils.isNotEmpty(groupParentIds)) {
                    // 1.1 批量查询所有影藏状态的父节点列表
                    List<UserGroupDO> parentGroups = userGroupDao.getByGroupIds(groupParentIds);
                    for (UserGroupDO parentGroup : parentGroups) {
                        // 判断该节点是否有其他的有效状态的子节点信息
                        Integer count = userGroupDao.getOtherChildrenCount(parentGroup.getGroupId(), Lists.newArrayList(UserGroupStatusEnum.ACTIVATED.getStatus()));
                        if (UserGroupStatusEnum.HIDDEN.getStatus().equals(parentGroup.getGroupStatus())) {
                            // 如果有则直接跳出
                            if (count != null && count > 0) {
                                lastNotHiddenGroup = parentGroup.getGroupId();
                                continue;
                            }
                            // 如果没有表示该节点需要被标记为删除
                            userGroupDao.updateStatusById(parentGroup.getGroupId(), UserGroupStatusEnum.DELETED.getStatus());
                            // 将该标记为删除的节点的所有【已失效】的子节点的parentIds去除当前节点的id,由于parentIds是排序的，所以删除指定位数上的即可
                            int seat = 0;
                            if (StringUtils.isNotBlank(parentGroup.getGroupParentIds())) {
                                seat += JSON.parseArray(parentGroup.getGroupParentIds(), String.class).size();
                            }
                            userGroupDao.deleteChildrenSeatLocationPids(parentGroup.getGroupId(), UserGroupStatusEnum.INACTIVATED.getStatus(), seat);
                        } else {
                            lastNotHiddenGroup = parentGroup.getGroupId();
                            if (count == null || count == 0) {
                                userGroupDao.updateHaveChildrenFlag(parentGroup.getGroupId(), 0);
                            }
                        }
                    }
                }
                // 2. 根据groupId更新并查询所有状态为【隐藏节点的】子节点的状态为已删除
                List<String> hiddenChildrenIds = userGroupDao.getChildrenIdsByStatus(groupId, UserGroupStatusEnum.HIDDEN.getStatus());
                // 3. 根据上一步所有已删除的节点id列表更新所有已失效子节点的parentIds去除删除的节点
                if (CollectionUtils.isNotEmpty(hiddenChildrenIds)) {
                    userGroupDao.updateChildrenStatus(hiddenChildrenIds, userId, UserGroupStatusEnum.DELETED.getStatus());
                    for (String deleteGroupId : hiddenChildrenIds) {
                        UserGroupDO temp = userGroupDao.getById(deleteGroupId);
                        if (null != temp) {
                            int seat = 0;
                            if (StringUtils.isNotBlank(temp.getGroupParentIds())) {
                                seat += JSON.parseArray(temp.getGroupParentIds(), String.class).size();
                            }
                            userGroupDao.deleteChildrenSeatLocationPids(deleteGroupId, UserGroupStatusEnum.INACTIVATED.getStatus(), seat);
                        }
                    }
                }

                // 4. 所有子节点的parentId更新为(从下往上)第一个正常的节点
                userGroupDao.refreshAllChildrenParentId(orgId, parentId, lastNotHiddenGroup);
            } finally {
                lock.unlock();
            }
        });
    }

    @Override
    public ServiceResult<List<String>> getChildrenGroupIdsByUserId(String orgId, String userId) {
        // 用户所在当前组以及所有子组
        Set<String> selfAndSubGroupIds = new HashSet<>();
        ServiceResult<List<UserWithGroupDTO>> userWithGroupResult = userUserGroupService.getUserWithGroup(userId);
        if (userWithGroupResult.isSuccess() && CollectionUtils.isNotEmpty(userWithGroupResult.getData())) {
            // 用户所在当前组
            List<String> currentGroupId = userWithGroupResult.getData().stream().map(UserWithGroupDTO::getId).collect(Collectors.toList());
            selfAndSubGroupIds.addAll(currentGroupId);
            for (String groupId : currentGroupId) {
                // 用户所在当前组及子组
                List<String> subGroupIds = userGroupDao.getSubGroupIds(orgId, groupId);
                selfAndSubGroupIds.addAll(subGroupIds);
            }
        }
        return ServiceResult.success(new ArrayList<>(selfAndSubGroupIds));
    }

    @Override
    public ServiceResult<UserGroupDO> getUserGroupByCondition(UserGroupDO userGroupDO) {
        UserGroupDO temp = userGroupDao.findOne(userGroupDO);
        return ServiceResult.success(temp);
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> getGroupsByUserIdLeftJoinGroup(String userId) {
        List<UserGroupDO> groups = userGroupDao.getGroupsByUserIdLeftJoinGroup(userId);
        return ServiceResult.success(userGroupConvert.dosToDtos(groups));
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> listByGroupIds(List<String> groupIds) {
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDao.listByGroupIds(groupIds)));
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> listByGroupIdsAndStatus(List<String> groupIds, Integer status) {
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDao.listByGroupIdsAndStatus(groupIds, status)));
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> listGroupsByCodes(String orgId, List<String> groupCodesList, List<Integer> statusList) {
        List<UserGroupDO> groups = userGroupDao.listGroupsByCodes(orgId, groupCodesList, statusList);
        return ServiceResult.success(userGroupConvert.dosToDtos(groups));
    }

    @Override
    public ServiceResult<Long> getUserNum(String groupId, String groupLevelId, String orgId, String userId) {
        // 参数校验
        UserGroupDO userGroup = userGroupDao.getById(groupId);
        if (Objects.isNull(userGroup) || !userGroup.getOrgId().equals(orgId)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, String.format("未查询到对应的组织信息, groupId:%s，orgId:%s", groupId, orgId));
        }
        // 获取租户下所有的层级列表
        ServiceResult<List<UserGroupLevelDTO>> groupLevelsResult = userGroupLevelService.listByOrgId(orgId);
        if (!groupLevelsResult.isSuccess() && CollectionUtils.isEmpty(groupLevelsResult.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, String.format("未查询到当前租户的层级列表信息, orgId:%s", orgId));
        }

        groupLevelId = groupLevelId.toLowerCase();
        Map<String, Integer> groupLevelNumMap = groupLevelsResult.getData().stream().collect(Collectors.toMap(UserGroupLevelDTO::getGroupLevelId, UserGroupLevelDTO::getLevelNum, (c1, c2) -> c2));
        if (!groupLevelNumMap.containsKey(groupLevelId)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, String.format("groupLevelId无效, groupLevelId:%s，orgId:%s", groupLevelId, orgId));
        }
        Integer currentLevelNum = groupLevelNumMap.get(userGroup.getGroupLevelId());
        Integer destLevelNum = groupLevelNumMap.get(groupLevelId);
        if (destLevelNum.compareTo(currentLevelNum) < 0) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, String.format("groupLevelId对应层级数不能比当前组织的层级高, groupLevelId:%s，groupId:%s", groupLevelId, groupId));
        }

        Long userNum = userGroupDao.getSelfAndChildrenUserNum(UserStatusEnum.ACTIVATED.getStatus(), groupId, groupLevelId, userId, UserGroupStatusEnum.ACTIVATED.getStatus());
        return ServiceResult.success(userNum);
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> listSubGroups(List<String> groupIds, String levelId) {
        // 参数校验
        if (CollectionUtils.isEmpty(groupIds)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "组织id列表不能为空！");
        }
        List<UserGroupDTO> result = new ArrayList<>();
        // 1. 根据groupIds查询所有的子节点信息
        List<UserGroupDO> groupDOS = userGroupDao.listChildrenByParentIds(groupIds);
        if (CollectionUtils.isNotEmpty(groupDOS)) {
            result.addAll(userGroupConvert.dosToDtos(groupDOS));
        }

        // 2. 根据groupIds和groupLevelId查询对应的节点信息
        List<UserGroupDO> groupDOS1 = userGroupDao.listByGroupIdsAndLevelId(groupIds, levelId);
        if (CollectionUtils.isNotEmpty(groupDOS1)) {
            result.addAll(userGroupConvert.dosToDtos(groupDOS1));
        }

        return ServiceResult.success(result);
    }

    @Override
    public ServiceResult<PageResponseDTO<UserGroupDTO>> searchGroups(SearchGroupsParam searchGroupsParam) {
        PageParam pageParam = searchGroupsParam.getPageParam();
        SearchGroupsDO searchGroupsDO = new SearchGroupsDO();
        BeanUtils.copyProperties(searchGroupsParam, searchGroupsDO);
        searchGroupsDO.setOffset(pageParam.getOffset());
        searchGroupsDO.setSize(pageParam.getSize());
        Long count = userGroupDao.searchGroupsCount(searchGroupsDO);
        if (count == 0L) {
            return ServiceResult.success(new PageResponseDTO<>(new ArrayList<>(), count, pageParam.getOffset()));
        }
        List<UserGroupDO> userGroupDOList = userGroupDao.searchGroups(searchGroupsDO);

        return ServiceResult.success(new PageResponseDTO<>(userGroupConvert.dosToDtos(userGroupDOList), count, pageParam.getOffset()));
    }

    @Override
    public ServiceResult<List<UserGroupDTO>> listGroupsByIds(List<String> groupIds) {
        if (CollectionUtils.isEmpty(groupIds)) {
            return ServiceResult.success(new ArrayList<>());
        }
        List<UserGroupDO> userGroupDOList = userGroupDao.listByGroupIds(groupIds);
        return ServiceResult.success(userGroupConvert.dosToDtos(userGroupDOList));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ServiceResult<String> saveGroupAndLevel(List<UserGroupLevelDTO> levelDTOS, List<UserGroupImportDTO> importDTOS, TokenDTO tokenDTO) {
        // 清除ThreadLocal
        UserGroupContextUtil.remove();

        // 1.设置保存层级参数
        // 查询公司层级
        ServiceResult<List<UserGroupLevelDTO>> levelResult = userGroupLevelService.listByOrgId(tokenDTO.getOrgId());
        if (!levelResult.isSuccess()) {
            return ServiceResult.fail(levelResult.getMsg());
        }
        List<UserGroupLevelDTO> levels = levelResult.getData();
        Map<String, UserGroupLevelDTO> existLevelMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(levels)) {
            existLevelMap = levels.stream().collect(Collectors.toMap(UserGroupLevelDTO::getGroupLevelName, v -> v));
        }

        // 最新的层级: 名称-id键值对
        Map<String, String> levelNameAndIdMap = new HashMap<>();
        Date now = new Date();
        // 需要更新的层级集合
        List<UserGroupLevelDTO> updateLevels = new ArrayList<>();
        // 需要新增的层级集合
        List<UserGroupLevelDTO> addLevels = new ArrayList<>();
        List<String> delLevelIds = null;
        List<String> updateLevelIds = new ArrayList<>();
        String levelChildrenId = null;
        String storeLevelId = null;
        int storeLevelSortNum = levelDTOS.size() - 1;
        for (int i = storeLevelSortNum; i >= 0; i--) {
            UserGroupLevelDTO levelDTO = new UserGroupLevelDTO();
            UserGroupLevelDTO existLevel = existLevelMap.get(levelDTOS.get(i).getGroupLevelName());
            levelDTO.setOrgId(tokenDTO.getOrgId());
            levelDTO.setOperatorId(tokenDTO.getUserId());
            levelDTO.setUpdateTime(now);
            levelDTO.setGroupLevelName(levelDTOS.get(i).getGroupLevelName());
            levelDTO.setLevelNum(i);
            levelDTO.setLevelChildrenId(levelChildrenId);

            if (existLevel != null) {
                levelDTO.setGroupLevelId(existLevel.getGroupLevelId());

                updateLevelIds.add(existLevel.getGroupLevelId());
                updateLevels.add(levelDTO);
                if (!levelDTO.getGroupLevelName().equals(existLevel.getGroupLevelName())) {
                    LevelNameInfo levelNameInfo = new LevelNameInfo();
                    levelNameInfo.setLevelId(levelDTO.getGroupLevelId());
                    levelNameInfo.setNewLevelName(levelDTO.getGroupLevelName());
                    levelNameInfo.setOldLevelName(existLevel.getGroupLevelName());
                    UserGroupContextUtil.addUpdateNameLevelItem(levelNameInfo);
                }

            } else {
                levelDTO.setGroupLevelId(ObjectId.next());
                levelDTO.setCreatorId(tokenDTO.getUserId());
                levelDTO.setCreateTime(now);
                levelDTO.setVersionId(UserGroupConstant.INITIAL_VERSION);
                addLevels.add(levelDTO);
            }

            // 设置门店levelId
            if (i == storeLevelSortNum) {
                storeLevelId = levelDTO.getGroupLevelId();
            }
            levelNameAndIdMap.put(levelDTO.getGroupLevelName(), levelDTO.getGroupLevelId());
            levelChildrenId = levelDTO.getGroupLevelId();
        }
        // 设值-层级名称与id Map集合
        UserGroupContextUtil.setLevelMap(levelNameAndIdMap);

        // 2.设置保存组织参数
        UserGroupDTO userGroupDTO = new UserGroupDTO();
        userGroupDTO.setOrgId(tokenDTO.getOrgId());
        ServiceResult<List<UserGroupDTO>> groupResult = userGroupService.listByCondition(userGroupDTO);
        if (!groupResult.isSuccess()) {
            return ServiceResult.fail(groupResult.getMsg());
        }
        List<UserGroupDTO> existGroups = groupResult.getData();

        if (CollectionUtils.isNotEmpty(existGroups)) {
            UserGroupContextUtil.setExistMap(existGroups.stream().filter(item -> GROUP_STATUS_ACTIVATED.getIndex().equals(item.getGroupStatus()) || GroupStatusEnum.GROUP_STATUS_INACTIVATED.getIndex().equals(item.getGroupStatus()) || GroupStatusEnum.GROUP_STATUS_HIDDEN.getIndex().equals(item.getGroupStatus())).collect(Collectors.groupingBy(UserGroupDTO::getGroupCode)));
        }

        ServiceResult<String> generateCodeResult = userGroupService.generateGroupCode();
        if (!generateCodeResult.isSuccess()) {
            return ServiceResult.fail(generateCodeResult.getMsg());
        }

        // 通过层级 + 父级组织 给组织分类
        Map<String, List<UserGroupImportDTO>> groupMap = importDTOS.stream().collect(Collectors.groupingBy(UserGroupImportDTO::getParentFullGroupName));
        UserGroupContextUtil.setImportMap(groupMap);

        // 获取根组织
        UserGroupImportDTO rootImportGroup = UserGroupContextUtil.getImportMap().get(StringUtils.EMPTY).get(0);
        // 设置根组织参数
        UserGroupDTO rootGroup = buildRootGroupParam(rootImportGroup, tokenDTO, now, storeLevelId);
        // 分层分父组织封装参数
        buildParamByLayer(rootGroup, rootImportGroup.getFullGroupName(), storeLevelId);

        // 存放失效组织id集合
        List<String> invalidGroupIds = new ArrayList<>();
        Map<String, List<UserGroupDTO>> existMap = UserGroupContextUtil.getExistMap();
        if (existMap != null && existMap.size() > 0) {
            for (Map.Entry<String, List<UserGroupDTO>> entry : existMap.entrySet()) {
                UserGroupDTO existUserGroup = entry.getValue().get(0);
                if (UserGroupStatusEnum.ACTIVATED.getStatus().equals(existUserGroup.getGroupStatus())) {
                    // 状态为活动的组织: 设置组织状态为失效
                    UserGroupDTO invalidGroup = new UserGroupDTO();
                    invalidGroup.setGroupId(existUserGroup.getGroupId());
                    invalidGroup.setGroupStatus(UserGroupStatusEnum.INACTIVATED.getStatus());
                    invalidGroup.setVersionId(existUserGroup.getVersionId() + 1);

                    invalidGroupIds.add(invalidGroup.getGroupId());
                    UserGroupContextUtil.addUpdateGroupsItem(invalidGroup);
                } else if (UserGroupStatusEnum.HIDDEN.getStatus().equals(existUserGroup.getGroupStatus())) {
                    // 状态为隐藏的组织: 设置组织状态为删除
                    UserGroupDTO delGroup = new UserGroupDTO();
                    delGroup.setGroupId(existUserGroup.getGroupId());
                    delGroup.setGroupStatus(UserGroupStatusEnum.DELETED.getStatus());
                    delGroup.setVersionId(existUserGroup.getVersionId() + 1);
                    delGroup.setOperatorId(rootGroup.getOperatorId());
                    delGroup.setUpdateTime(rootGroup.getUpdateTime());
                    UserGroupContextUtil.addUpdateGroupsItem(delGroup);
                }
            }
        }
        // 设置失效组织id集合
        UserGroupContextUtil.setInvalidGroups(invalidGroupIds);

        // 保存层级
        // 设置要删除的层级
        if (CollectionUtils.isNotEmpty(levels)) {
            delLevelIds = levels.stream().filter(v -> !updateLevelIds.contains(v.getGroupLevelId())).map(UserGroupLevelDTO::getGroupLevelId).collect(Collectors.toList());
        }
        UserGroupContextUtil.setDelLevelId(delLevelIds);
        // 新增层级
        if (CollectionUtils.isNotEmpty(addLevels)) {
            ServiceResult<Boolean> addLevelResult = userGroupLevelService.insertBatch(addLevels);
            if (!addLevelResult.isSuccess()) {
                return ServiceResult.fail(addLevelResult.getMsg());
            }
        }
        // 删除层级
        if (CollectionUtils.isNotEmpty(delLevelIds)) {
            ServiceResult<Integer> delLevelResult = userGroupLevelService.deleteByIds(delLevelIds);
            if (!delLevelResult.isSuccess()) {
                return ServiceResult.fail(delLevelResult.getMsg());
            }
        }
        // 更新层级
        if (CollectionUtils.isNotEmpty(updateLevels)) {
            for (UserGroupLevelDTO updateLevel : updateLevels) {
                userGroupLevelService.updateById(updateLevel);
            }
        }

        // 保存组织
        // 新增组织集合
        List<UserGroupDTO> addGroups = UserGroupContextUtil.getAddGroups();
        if (CollectionUtils.isNotEmpty(addGroups)) {
            userGroupService.insertBatch(addGroups);
        }

        // 更新组织集合
        List<UserGroupDTO> updateGroups = UserGroupContextUtil.getUpdateGroups();
        if (CollectionUtils.isNotEmpty(updateGroups)) {
            for (UserGroupDTO updateGroup : updateGroups) {
                userGroupService.updateByIdAndVersionWithNull(updateGroup.getVersionId() - 1, updateGroup);
            }
        }

        // 3.更新公司的rootGroupId： 通过公司id更新rootGroupId
        OrganizationDTO updateParam = new OrganizationDTO();
        updateParam.setOrgId(rootGroup.getOrgId());
        updateParam.setRootGroupId(rootGroup.getGroupId());
        organizationService.updateByPrimaryKeySelective(updateParam);

        // 4.更新组织树的版本号
        groupSequenceUtil.incrementVersion(tokenDTO.getOrgId());

        return ServiceResult.success(rootGroup.getGroupId());
    }

    private String generateCode() {
        return userGroupService.generateGroupCode().getData();
    }

    /**
     * 设置根组织参数
     *
     * @param rootImportGroup
     * @param tokenDTO
     * @param now
     * @param storeLevelId
     * @return
     */
    @Override
    public UserGroupDTO buildRootGroupParam(UserGroupImportDTO rootImportGroup, TokenDTO tokenDTO, Date now, String storeLevelId) {
        UserGroupDTO parentGroup = new UserGroupDTO();
        List<String> groupParentIds = new ArrayList<>();
        parentGroup.setGroupParentIds(JSON.toJSONString(groupParentIds));
        parentGroup.setOrgId(tokenDTO.getOrgId());
        parentGroup.setOperatorId(tokenDTO.getUserId());
        parentGroup.setUpdateTime(now);

        return buildGroupParam(parentGroup, rootImportGroup, NumberUtils.INTEGER_ONE, storeLevelId);
    }

    @Override
    public void buildParamByLayer(UserGroupDTO parentGroup, String parentFullGroupName, String storeLevelId) {
        // 获取当前父组织的子组织集合
        List<UserGroupImportDTO> childGroups = UserGroupContextUtil.getImportMap().get(parentFullGroupName);
        if (CollectionUtils.isEmpty(childGroups)) {
            parentGroup.setHaveChildrenFlag(HaveChildrenFlagEnum.NOT_HAVE.getStatus());
            return;
        }
        parentGroup.setHaveChildrenFlag(HaveChildrenFlagEnum.HAVE.getStatus());

        // 设置排序初始值
        int groupOrder = NumberUtils.INTEGER_ONE;
        for (UserGroupImportDTO childGroup : childGroups) {
            // 设值子节点
            UserGroupDTO userGroup = buildGroupParam(parentGroup, childGroup, UserGroupStatusEnum.ACTIVATED.getStatus().equals(childGroup.getGroupStatus()) ? groupOrder : NumberUtils.INTEGER_ONE, storeLevelId);
            // 设值子节点的子节点
            buildParamByLayer(userGroup, childGroup.getFullGroupName(), storeLevelId);
            // 设值活动状态的组织 子节点排序自增
            if (UserGroupStatusEnum.ACTIVATED.getStatus().equals(childGroup.getGroupStatus())) {
                groupOrder++;
            }
        }
    }

    /**
     * 设置组织参数
     *
     * @param parentGroup
     * @param importGroup
     * @param groupOrder
     * @param storeLevelId
     * @return
     */
    @Override
    public UserGroupDTO buildGroupParam(UserGroupDTO parentGroup, UserGroupImportDTO importGroup, int groupOrder, String storeLevelId) {
        // 判断组织编码是否为空,是的话则设置自动生成的编码
        if (StringUtils.isBlank(importGroup.getGroupCode())) {
            // 设置自动生成的组织编码
            importGroup.setGroupCode(this.generateCode());
        }

        UserGroupDTO userGroup = new UserGroupDTO();
        userGroup.setOrgId(parentGroup.getOrgId());
        userGroup.setOperatorId(parentGroup.getOperatorId());
        userGroup.setUpdateTime(parentGroup.getUpdateTime());
        userGroup.setGroupName(importGroup.getGroupName());
        userGroup.setGroupStatus(importGroup.getGroupStatus());
        userGroup.setGroupLevelId(UserGroupContextUtil.getLevelMap().get(importGroup.getGroupLevelName()));
        userGroup.setGroupParentId(parentGroup.getGroupId());
        userGroup.setHaveChildrenFlag(importGroup.getHaveChildrenFlag());

        // 设置祖先节点id集合
        List<String> groupParentIds = JSON.parseArray(parentGroup.getGroupParentIds(), String.class);
        if (StringUtils.isNotBlank(parentGroup.getGroupId())) {
            groupParentIds.add(parentGroup.getGroupId());
        }
        userGroup.setGroupParentIds(JSON.toJSONString(groupParentIds));

        // 设置组织编码
        userGroup.setGroupCode(importGroup.getGroupCode());
        // 设置组织排序
        userGroup.setGroupOrder(groupOrder);
        // 设置组织负责人
        userGroup.setAdminId(importGroup.getAdminId());

        // 设置组织id
        List<UserGroupDTO> existGroupList = null;
        if (StringUtils.isNotBlank(userGroup.getGroupCode()) && UserGroupContextUtil.getExistMap() != null) {
            existGroupList = UserGroupContextUtil.getExistMap().get(importGroup.getGroupCode());
        }

        // 如果是根组织,则需要判断是否存在, 如果不存在则需要新增, 如果存在则只需更新: 根组织id唯一。根组织编码清空或修改，系统仅更新组织编码，但根组织还是原来那个根组织不变。
        if (StringUtils.isBlank(userGroup.getGroupParentId())) {
            // 通过公司id获取公司根组织信息 rootGroupId
            OrganizationDTO organizationDTO = organizationService.selectByPrimaryKey(userGroup.getOrgId()).getData();
            // 通过接口返回的公司信息,得到根组织id
            if (StringUtils.isNotBlank(organizationDTO.getRootGroupId())) {
                UserGroupDTO existRootGroup = userGroupService.getByIdAndOrgId(organizationDTO.getRootGroupId(), userGroup.getOrgId()).getData();
                if (existRootGroup != null) {
                    existGroupList = Collections.singletonList(existRootGroup);

                    // 删除已存在根组织
                    UserGroupContextUtil.delExistMapItem(existRootGroup.getGroupCode(), existRootGroup.getGroupId());

                    if (!existRootGroup.getGroupCode().equals(userGroup.getGroupCode())) {
                        // 根组织的组织编码发生变动时，解除绑定在根组织的账号和组织负责人(如果未传递组织负责人)
                        userUserGroupService.deleteByGroupId(existRootGroup.getGroupId());
                        if (StringUtils.isBlank(userGroup.getAdminId())) {
                            userGroup.setAdminId(StringUtils.EMPTY);
                        }
                    }
                }
            }
        }

        if (CollectionUtils.isEmpty(existGroupList)) {
            // 新增
            userGroup.setCreatorId(parentGroup.getOperatorId());
            userGroup.setCreateTime(parentGroup.getUpdateTime());
            userGroup.setGroupType(UserGroupTypeEnum.DEFAULT.getCode());

            userGroup.setGroupId(ObjectId.next());
            userGroup.setVersionId(UserGroupConstant.INITIAL_VERSION);
            userGroup.setSeq(sequenceService.incrementVersion(userCacheUtil.buildKey(UserCacheKeyConstant.USER_GROUP_SEQ, userGroup.getOrgId())));

            // 添加新增组织
            UserGroupContextUtil.addAddGroupsItem(userGroup);
            if (storeLevelId.equals(userGroup.getGroupLevelId())) {
                // 添加新增门店组织
                StoreInfo storeInfo = new StoreInfo(userGroup.getGroupId(), userGroup.getGroupCode(), userGroup.getGroupName(), null);
                UserGroupContextUtil.addAddStoreGroupsItem(storeInfo);
            }
        } else {
            // 更新
            UserGroupDTO existGroup = existGroupList.get(0);
            userGroup.setGroupId(existGroup.getGroupId());
            userGroup.setVersionId(existGroup.getVersionId() + 1);

            // 删除已存在组织
            UserGroupContextUtil.delExistMapItem(importGroup.getGroupCode(), userGroup.getGroupId());
            if (UserGroupStatusEnum.ACTIVATED.getStatus().equals(existGroup.getGroupStatus())) {
                if (!userGroup.getGroupName().equals(existGroup.getGroupName())) {
                    // 添加组织名称变化组织
                    GroupNameInfo groupNameInfo = new GroupNameInfo();
                    groupNameInfo.setGroupId(userGroup.getGroupId());
                    groupNameInfo.setNewGroupName(userGroup.getGroupName());
                    groupNameInfo.setOldGroupName(existGroup.getGroupName());
                    UserGroupContextUtil.addUpdateNameGroupsItem(groupNameInfo);
                }
            } else if (UserGroupStatusEnum.INACTIVATED.getStatus().equals(existGroup.getGroupStatus())) {
                if (!userGroup.getGroupName().equals(existGroup.getGroupName())) {
                    // 添加组织名称变化组织
                    GroupNameInfo groupNameInfo = new GroupNameInfo();
                    groupNameInfo.setGroupId(userGroup.getGroupId());
                    groupNameInfo.setNewGroupName(userGroup.getGroupName());
                    groupNameInfo.setOldGroupName(existGroup.getGroupName());
                    UserGroupContextUtil.addUpdateNameGroupsItem(groupNameInfo);
                }
                // 添加恢复失效组织
                UserGroupContextUtil.addResumeGroupsItem(userGroup.getGroupId());
            }

            // 添加更新组织
            UserGroupContextUtil.addUpdateGroupsItem(userGroup);
        }
        return userGroup;
    }

    @Override
    public List<UserGroupDTO> getSeqAndOrgId(Integer offset, Integer size) {
        return userGroupConvert.dosToDtos(userGroupDao.getSeqAndOrgId(offset, size));
    }

    /**
     * 获取用户直接关联的组织id，及他们的父组织id
     *
     * @param userId 用户id
     */
    private Set<String> getRelationAndParentGroupIdsOfUser(String userId) {
        Set<String> groupIds = new HashSet<>();
        // 用户直接关联的组织节点
        List<UserGroupDO> userGroupList = userGroupDao.listGroupByUserId(userId);
        for (UserGroupDO userGroupDO : userGroupList) {
            groupIds.add(userGroupDO.getGroupId());
            String groupParentIds = userGroupDO.getGroupParentIds();
            if (groupParentIds != null) {
                groupIds.addAll(JSON.parseArray(groupParentIds, String.class));
            }
        }
        return groupIds;
    }

    @Override
    public List<UserGroupDTO> listByOrgIdAndStatuses(String orgId) {
        return userGroupConvert.dosToDtos(userGroupDao.listByOrgIdAndStatuses(orgId, UserGroupStatusEnum.ACTIVATED.getStatus(), UserGroupStatusEnum.HIDDEN.getStatus()));
    }

    @Override
    public ServiceResult<Integer> deleteInvalidGroup(String userId, List<String> groupIdList) {
        List<UserGroupDO> userGroupList = userGroupDao.listByGroupIds(groupIdList);
        for (UserGroupDO userGroupDO : userGroupList) {
            if (!userGroupDO.getGroupStatus().equals(UserGroupStatusEnum.INACTIVATED.getStatus())) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "非失效的组织不允许删除");
            }
        }
        Integer result = 0;
        if (CollectionUtils.isNotEmpty(groupIdList)) {
            result = userGroupDao.deleteInvalidGroup(groupIdList);
        }
        return ServiceResult.success(result);
    }

    @Override
    public ServiceResult<PageResponseDTO<String>> listSubGroupIdsByGroupId(String orgId, String groupId, int page, int size) {
        PageResponseDTO<String> pageResponseDTO = new PageResponseDTO<>();
        Long total = userGroupDao.countChildrenByParentId(orgId, groupId);
        int start = (page - 1) * size;
        List<String> allIds = new ArrayList<>();
        if (total > 0 && start < total) {
            allIds = userGroupDao.listChildrenByParentId(orgId, groupId, page, size);
        }
        // 最后一页包括自身
        long totalPage = total / size;
        if (total % size > 0) {
            totalPage++;
        }
        if (totalPage == page && allIds.size() < size) {
            allIds.add(groupId);
        }
        if (start == total) {
            allIds.add(groupId);
        }

        pageResponseDTO.setTotal(total + 1);
        pageResponseDTO.setRows(allIds);
        return ServiceResult.success(pageResponseDTO);
    }

    @Override
    public List<String> getGroupParentIds(String groupId, List<String> parentIdList) {
        UserGroupDO parent = userGroupDao.getById(groupId);
        if (Objects.nonNull(parent)) {
            parentIdList.add(0, parent.getGroupId());
            if (StringUtils.isNotBlank(parent.getGroupParentId())) {
                getGroupParentIds(parent.getGroupParentId(), parentIdList);
            }
        }
        return parentIdList;
    }

    @Override
    public ServiceResult<GroupOldAllTreeDTO> getOldGroupTree(String orgId, String userId, boolean admin) {
        long startTime = System.currentTimeMillis();
        List<UserGroup> groupsOfOrg = userGroupMapper.listByOrgIdAndStatuses(orgId, UserGroupStatusEnum.ACTIVATED.getStatus(), UserGroupStatusEnum.HIDDEN.getStatus());
        log.info("[getOldGroupTree], {}耗时：{}", "查询groupsOfOrg", System.currentTimeMillis() - startTime);
        startTime = System.currentTimeMillis();
        // 如果不展示所有，且不是超管和系统管理员，则对groupsOfOrg进行过滤
        if (!admin) {
            List<UserGroup> groupsOfUser = userGroupMapper.listByUserIdAndStatus(userId, UserGroupStatusEnum.ACTIVATED.getStatus());
            log.info("[getOldGroupTree], {}耗时：{}", "查询groupsOfUser", System.currentTimeMillis() - startTime);
            startTime = System.currentTimeMillis();
            if (groupsOfUser == null || groupsOfUser.isEmpty()) {
                // 如果普通操作员未挂到任何组织上，则不返回任何组织
                return ServiceResult.fail(ResourceErrorCodeEnum.OUT_OF_GROUP, "current user is out of group");
            }
            Set<String> parentIds = new HashSet<>();
            Set<String> currentIds = new HashSet<>();
            // 普通操作员只展示关联组织，及其上下级
            for (UserGroup userGroup : groupsOfUser) {
                currentIds.add(userGroup.getGroupId());
                parentIds.add(userGroup.getGroupId());
                if (userGroup.getGroupParentIds() != null) {
                    List<String> parentGroupIds = JSON.parseArray(userGroup.getGroupParentIds(), String.class);
                    parentIds.addAll(parentGroupIds);
                }
            }
            // 过滤groupsOfOrg，过滤出用户有查看权限的节点
            groupsOfOrg = groupsOfOrg.stream().filter(group -> {
                // 用户绑定的节点，及这些节点的父节点
                if (parentIds.contains(group.getGroupId())) {
                    return true;
                }
                // 用户绑定的节点的子节点
                return currentIds.stream().anyMatch(groupId -> {
                    List<String> parentGroupIds = JSON.parseArray(group.getGroupParentIds(), String.class);
                    return parentGroupIds.contains(groupId);
                });
            }).collect(Collectors.toList());
            log.info("{}耗时：{}", "过滤groupsOfOrg，过滤出用户有查看权限的节点", System.currentTimeMillis() - startTime);
        }
        groupsOfOrg = Optional.ofNullable(groupsOfOrg).orElse(new ArrayList<>());
        List<String> needLevels = groupsOfOrg.stream().map(UserGroup::getGroupLevelId).distinct().collect(Collectors.toList());
        List<UserGroupLevelDTO> levelDTOs = userGroupLevelService.listByOrgId(orgId).getData();
        List<UserGroupLevelDTO> filterLevels = levelDTOs.stream().filter(l -> needLevels.contains(l.getGroupLevelId())).collect(Collectors.toList());
        GroupOldAllTreeDTO allTreeDTO = new GroupOldAllTreeDTO();
        if (CollectionUtils.isNotEmpty(filterLevels)) {
            filterLevels.sort(Comparator.comparing(UserGroupLevelDTO::getLevelNum));
            List<String> levels = filterLevels.stream().map(UserGroupLevelDTO::getGroupLevelName).collect(Collectors.toList());
            List<GroupOldLevelTreeDTO> groupLevelList = new ArrayList<>();
            for (UserGroupLevelDTO groupLevelDTO : filterLevels) {
                GroupOldLevelTreeDTO oldLevelTreeDTO = new GroupOldLevelTreeDTO();
                oldLevelTreeDTO.setId(groupLevelDTO.getGroupLevelId());
                oldLevelTreeDTO.setTitle(groupLevelDTO.getGroupLevelName());
                groupLevelList.add(oldLevelTreeDTO);
            }
            allTreeDTO.setLevels(levels);
            allTreeDTO.setGroupLevelList(groupLevelList);
        }
        // 组装成组织tree
        allTreeDTO.setTree(list2OldTree(groupsOfOrg, filterLevels));
        allTreeDTO.setVersion(groupSequenceUtil.getVersion(orgId));
        return ServiceResult.success(allTreeDTO);
    }

    /**
     * 找到根节点，并将list拼装成组织树
     */
    private GroupOldTreeDTO list2OldTree(List<UserGroup> list, List<UserGroupLevelDTO> filterLevels) {
        // 找到根节点
        List<UserGroup> roots = list.stream().filter(userGroup1 -> userGroup1.getGroupParentId() == null).collect(Collectors.toList());
        if (roots.size() > 1) {
            throw new RuntimeException("不能有多个根节点");
        }
        if (roots.isEmpty()) {
            return null;
        }
        UserGroup root = roots.get(0);
        // 拼装成树形结构
        return genOldTreeNode(list, root, filterLevels);
    }

    /**
     * 递归拼装组织层级树，每次拼装一个节点
     *
     * @param list         待拼装的组织列表
     * @param group        从该组织节点开始拼装
     * @param filterLevels 从该组织节点开始拼装
     * @return 递归生成的树
     */
    private GroupOldTreeDTO genOldTreeNode(List<UserGroup> list, UserGroup group, List<UserGroupLevelDTO> filterLevels) {
        GroupOldTreeDTO dto = convertToDto(group, filterLevels);
        List<GroupOldTreeDTO> subList = new LinkedList<>();
        for (UserGroup userGroup : list) {
            // 递归拼装数据
            if (userGroup.getGroupParentId() != null && userGroup.getGroupParentId().equals(group.getGroupId())) {
                subList.add(genOldTreeNode(list, userGroup, filterLevels));
            }
        }
        if (subList.size() > 0) {
            dto.setChildren(subList);
        }
        return dto;
    }

    private GroupOldTreeDTO convertToDto(UserGroup group, List<UserGroupLevelDTO> filterLevels) {
        GroupOldTreeDTO dto = new GroupOldTreeDTO();
        dto.setAdminID(group.getAdminId()).setCode(group.getGroupCode()).setEditable(true).setId(group.getGroupId()).setIsLeaf(group.getHaveChildrenFlag() <= 0).setSeq(group.getSeq()).setStatus(group.getGroupStatus()).setTitle(group.getGroupName());
        Optional<UserGroupLevelDTO> groupLevelDTO = filterLevels.stream().filter(l -> l.getGroupLevelId().equals(group.getGroupLevelId())).findFirst();
        groupLevelDTO.ifPresent(userGroupLevelDTO -> dto.setLevel(userGroupLevelDTO.getLevelNum()));
        dto.setUserCount(userUserGroupMapper.getUserCountByGroupId(group.getGroupId()));
        return dto;
    }


    @Override
    public ServiceResult<?> userGroup(boolean onlyValidate, Integer page, Integer rowsPerPage, Integer status, String search) {
        if (Objects.nonNull(page) || Objects.nonNull(rowsPerPage)) {
            //if self.pop_argument('currentLevel'):
            UserGroup userGroup = new UserGroup();
            userGroup.setGroupStatus(status);
            List<UserGroup> data = userGroupMapper.selectPageBySelective(userGroup, search, rowsPerPage, (page - 1) * rowsPerPage);
            List<JSONObject> res = data.stream().map(v -> {
                JSONObject obj = new JSONObject();
                obj.put("id", v.getGroupId());
                obj.put("code", v.getGroupCode());
                obj.put("seq", v.getSeq());
                obj.put("title", v.getGroupName());
                obj.put("groupLevelID", v.getGroupLevelId());
                obj.put("status", v.getGroupStatus());
                obj.put("parentID", v.getGroupParentId());
                obj.put("adminID", v.getAdminId());
                return obj;
            }).collect(Collectors.toList());
            //参照py取部分字段
            Long count = userGroupMapper.countBySelective(userGroup, search);
            if (count <= 0) {
                PageResponseDTO<User> pageret = new PageResponseDTO<>();
                pageret.setTotal(0L);
                return ServiceResult.success(pageret);
            }
            PageResponseDTO<JSONObject> pageret = new PageResponseDTO<>(res, count, page);
            return ServiceResult.success(pageret);
        }
        OrganizationDO organizationDO = organizationDao.selectByPrimaryKey(SecurityContextHolder.getOrgId());
        List<String> group_ids = new ArrayList<>();
        Integer superRole = SecurityContextHolder.getToken().getSuperRole();
        if (SecurityContextHolder.getToken().getSuperRole() == 1) {
            group_ids.add(organizationDO.getRootGroupId());
        } else {
            group_ids = getUserGroupIds(SecurityContextHolder.getUserId(), null, false);
        }
        return ServiceResult.success(getSubGroupList(organizationDO.getOrgId(), group_ids, onlyValidate, superRole));
    }


    private List<Map> getSubGroupList(String orgId, List<String> group_ids, boolean onlyValidate, Integer superRole) {
        List<UserGroupDTO> group_data = listByOrgId(orgId).getData();
        Map<String, UserGroupDTO> group_data_dict = group_data.stream().collect(Collectors.toMap(UserGroupDTO::getGroupId, Function.identity()));
        Map<Integer, List<Map>> group_dict = new HashMap();
        if (superRole != 1) {
            List<UserGroupDTO> finalGroup_data = group_data;
            //以下写法会抛出ConcurrentModificationException异常
            //group_ids.forEach(gid -> group_ids.addAll(recursionGetGroupChildrenListByData(gid, finalGroup_data)));
            for (int i = 0; i < group_ids.size(); i++) {
                group_ids.addAll(recursionGetGroupChildrenListByData(group_ids.get(i), finalGroup_data));
            }
            List<UserGroupDTO> groups = group_data.stream()
                    .filter(v -> group_ids.contains(v.getGroupId()) && (!onlyValidate || GROUP_STATUS_ACTIVATED.getIndex().equals(v.getGroupStatus())))
                    .collect(Collectors.toList());
            getGroupDict(groups, group_data_dict, group_dict);
        } else {
            group_data = group_data.stream().filter(v -> GROUP_STATUS_ACTIVATED.getIndex().equals(v.getGroupStatus())).collect(Collectors.toList());
            getGroupDict(group_data, group_data_dict, group_dict);
        }
        List<Map> group_list = new ArrayList<>();
        if (onlyValidate) {
            group_dict.values().forEach(group_list::addAll);
        } else {
            Integer anc_key = Collections.min(group_dict.keySet());
            while (CollUtil.isNotEmpty(group_dict.get(anc_key))) {
                group_list.addAll(group_dict.get(anc_key));
                anc_key += 1;
            }
        }
        return group_list;
    }

    private void getGroupDict(List<UserGroupDTO> groups, Map<String, UserGroupDTO> group_data_dict, Map<Integer, List<Map>> group_dict) {
        groups.forEach(data -> {
            List<String> ancestors = getGroupAncestorsByGroupIdGroupData(data.getGroupId(), group_data_dict);
            Map<String, Object> value = new HashMap<>(4);
            value.put("id", data.getGroupId());
            value.put("title", data.getGroupName());
            group_dict.compute(ancestors.size(), (k, v) -> {
                if (Objects.isNull(v)) {
                    v = new ArrayList();
                }
                v.add(value);
                return v;
            });
        });
    }

    /**
     * 递归查询当前节点的所有子节点
     *
     * @param group_id
     * @param group_data
     */
    private List<String> recursionGetGroupChildrenListByData(String group_id, List<UserGroupDTO> group_data) {
        List<String> children_list = new ArrayList<>();
        List<UserGroupDTO> c_group_list = group_data.stream().filter(v -> group_id.equals(v.getGroupParentId())).collect(Collectors.toList());
        while (!c_group_list.isEmpty()) {
            List<String> parent_list = new ArrayList<>();
            c_group_list.forEach(c_group -> {
                children_list.add(c_group.getGroupId());
                parent_list.add(c_group.getGroupId());
            });
            c_group_list = group_data.stream().filter(v -> parent_list.contains(v)).collect(Collectors.toList());
        }
        return children_list;
    }


    @Override
    public List<String> getUserGroupIds(String userId, String root_group_id, boolean is_filter_status) {
        List<String> group_ids = userUserGroupMapper.listByUserIdAndGroupIds(userId, Optional.ofNullable(root_group_id).map(Arrays::asList).orElse(null)).stream().map(UserUserGroup::getGroupId).collect(Collectors.toList());
        List<String> new_group_ids = null;
        if (group_ids.size() > 0) {
            new_group_ids = userGroupMapper.selectByIds(group_ids).stream()
                    .filter(v -> !is_filter_status || (is_filter_status && GROUP_STATUS_ACTIVATED.getIndex().equals(v.getGroupStatus())))
                    .map(UserGroup::getGroupId).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(new_group_ids)) {
            throw new BusinessException(String.valueOf(OUT_OF_GROUP), "current user is out of group");
        }
        return new_group_ids;
    }

    @Override
    public Boolean groupCodeEditable(String id) {
        return bpSurveyQuotaGrpcService.surveyGroupIsInUse(id);
    }

    @Override
    public ServiceResult<?> groupUser(String id, Integer page, Integer rowsPerPage, Integer returnCount) {
        TokenDTO token = SecurityContextHolder.getToken();
        Integer superRole = token.getSuperRole();
        String userId = token.getUserId();
        List<UserGroup> group_list = new ArrayList<>();
        if (superRole != 1) {
            //这个地方可以优化为联表查询
            UserUserGroup userUserGroup = new UserUserGroup();
            userUserGroup.setUserGroupId(userId);
            List<UserUserGroup> cursor = userUserGroupMapper.selectBySelective(userUserGroup);
            for (UserUserGroup userGroup : cursor) {
                UserGroup group = userGroupMapper.selectByPrimaryKey(userGroup.getGroupId());
                if (Objects.nonNull(group)) {
                    group_list.add(group);
                }
            }
            //判断查询组是否是所在组或子组
            UserGroup group = userGroupMapper.selectByPrimaryKey(id);
            List<String> group_id_list = group_list.stream().map(UserGroup::getGroupId).collect(Collectors.toList());
            List<String> group_ancestors = getGroupAncestorsByGroupId(group.getGroupId()).getData();
            //返回用户数不校验可见范围
            if (Objects.nonNull(returnCount) && !group_id_list.contains(group.getGroupId())
                    && group_list.stream().noneMatch(v -> group_ancestors.contains(v.getGroupId()))) {
                throw new BusinessException(String.valueOf(PERMISSION_DENY.getCode()), String.format("no permission access to group[id=%s]", id));
            }
        }
        List<String> user_ids = getUserIdsInGroup(Arrays.asList(id));
        /*if (Objects.nonNull(returnCount)) {
            Map res = new HashMap(2);
            res.put("count", user_ids.size());
            return ServiceResult.success(res);
        }*/
        if (user_ids.size() > 0) {
            List<User> items = userAccountMapper.pageUserByIds(user_ids, rowsPerPage, (page - 1) * rowsPerPage);
            user_ids = items.stream().map(User::getUserId).collect(Collectors.toList());
            Map<String, List<Role>> userRoleDict = getUserRoleDict(user_ids);
            items.forEach(v -> {
                v.setRoleList(userRoleDict.getOrDefault(v.getUserId(), Collections.emptyList()));
                //隐藏字段数据
                v.setPassword(null);
                v.setSalt(null);
            });
            Long count = userAccountMapper.countUserByIds(user_ids);
            PageResponseDTO<User> pageret = new PageResponseDTO<>();
            if (count <= 0) {
                pageret.setTotal(0L);
                return ServiceResult.success(pageret);
            }
            pageret = new PageResponseDTO<>(items, count, page);
            return ServiceResult.success(pageret);
        } else {
            PageResponseDTO<User> pageret = new PageResponseDTO<>(Collections.emptyList(), 0L, page);
            return ServiceResult.success(pageret);
        }
    }

    private Map<String, List<Role>> getUserRoleDict(List<String> user_ids) {
        List<User> usersRoleList = xmUserRoleMapper.listUserIdAndRoleList(user_ids);
        return usersRoleList.stream().collect(Collectors.toMap(User::getUserId, User::getRoleList));
    }

    /**
     * 返回指定组下的所有用户ID，不包含子组
     *
     * @param group_id 一个组ID
     */
    private List<String> getUserIdsInGroup(List<String> group_id) {
        List<String> userIdsByGroupIds = userUserGroupMapper.getUserIdsByGroupIds(0, 0, group_id);
        return userIdsByGroupIds.stream().distinct().collect(Collectors.toList());
    }

    @Override
    public Boolean groupCodeCheck(String id, String code) {
        UserGroup group = new UserGroup();
        group.setOrgId(SecurityContextHolder.getOrgId());
        group.setGroupCode(code);
        group.setGroupStatus(GROUP_STATUS_INACTIVATED.getIndex());
        return userGroupMapper.selectBySelective(group, null).size() == 0;
    }
}
